<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "domain.h"
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/closuretask.h>
#include <vespa/fastos/file.h>
#include <algorithm>

#include <vespa/log/log.h>
LOG_SETUP(".transactionlog.domain");

using vespalib::string;
using vespalib::make_string;
using vespalib::LockGuard;
using vespalib::makeTask;
using vespalib::makeClosure;
using vespalib::Monitor;
using vespalib::MonitorGuard;
using search::common::FileHeaderContext;
using std::runtime_error;

namespace search::transactionlog {

Domain::Domain(const string &domainName, const string & baseDir, Executor & commitExecutor,
               Executor & sessionExecutor, uint64_t domainPartSize, DomainPart::Crc defaultCrcType,
               const FileHeaderContext &fileHeaderContext) :
    _defaultCrcType(defaultCrcType),
    _commitExecutor(commitExecutor),
    _sessionExecutor(sessionExecutor),
    _sessionId(1),
    _syncMonitor(),
    _pendingSync(false),
    _name(domainName),
    _domainPartSize(domainPartSize),
    _parts(),
    _lock(),
    _sessionLock(),
    _sessions(),
    _baseDir(baseDir),
    _fileHeaderContext(fileHeaderContext),
    _markedDeleted(false)
{
    int retval(0);
    if ((retval = makeDirectory(_baseDir.c_str())) != 0) {
        throw runtime_error(make_string("Failed creating basedirectory %s r(%d), e(%d)", _baseDir.c_str(), retval, errno));
    }
    if ((retval = makeDirectory(dir().c_str())) != 0) {
        throw runtime_error(make_string("Failed creating domaindir %s r(%d), e(%d)", dir().c_str(), retval, errno));
    }
    SerialNumList partIdVector = scanDir();
    const int64_t lastPart = partIdVector.empty() ? 0 : partIdVector.back();
    for (const int64_t partId : partIdVector) {
        if ( partId != -1) {
            _sessionExecutor.execute(makeTask(makeClosure(this, &Domain::addPart, partId, partId == lastPart)));
        }
    }
    _sessionExecutor.sync();
    if (_parts.empty() || _parts.crbegin()->second->isClosed()) {
        _parts[lastPart].reset(new DomainPart(_name, dir(), lastPart, _defaultCrcType, _fileHeaderContext, false));
    }
}

void Domain::addPart(int64_t partId, bool isLastPart) {
    DomainPart::SP dp(new DomainPart(_name, dir(), partId, _defaultCrcType, _fileHeaderContext, isLastPart));
    if (dp->size() == 0) {
        // Only last domain part is allowed to be truncated down to
        // empty size.
        assert(isLastPart);
        dp->erase(dp->range().to() + 1);
    } else {
        {
            LockGuard guard(_lock);
            _parts[partId] = dp;
        }
        if (! isLastPart) {
            dp->close();
        }
    }
}

class Sync : public vespalib::Executor::Task
{
public:
    Sync(Monitor &syncMonitor, const DomainPart::SP &dp, bool &pendingSync) :
        _syncMonitor(syncMonitor),
        _dp(dp),
        _pendingSync(pendingSync)
    { }
private:
    void run() override {
        _dp->sync();
        MonitorGuard guard(_syncMonitor);
        _pendingSync = false;
        guard.broadcast();
    }

    Monitor           & _syncMonitor;
    DomainPart::SP      _dp;
    bool              & _pendingSync;
};

Domain::~Domain() { }

DomainInfo
Domain::getDomainInfo() const
{
    LockGuard guard(_lock);
    DomainInfo info(SerialNumRange(begin(guard), end(guard)), size(guard), byteSize(guard));
    for (const auto &entry: _parts) {
        const DomainPart &part = *entry.second;
        info.parts.emplace_back(PartInfo(part.range(), part.size(), part.byteSize(), part.fileName()));
    }
    return info;
}

SerialNum
Domain::begin() const
{
    return begin(LockGuard(_lock));
}

SerialNum
Domain::begin(const LockGuard & guard) const
{
    (void) guard;
    assert(guard.locks(_lock));
    SerialNum s(0);
    if ( ! _parts.empty() ) {
        s = _parts.begin()->second->range().from();
    }
    return s;
}

SerialNum
Domain::end() const
{
    return end(LockGuard(_lock));
}

SerialNum
Domain::end(const LockGuard & guard) const
{
    (void) guard;
    assert(guard.locks(_lock));
    SerialNum s(0);
    if ( ! _parts.empty() ) {
        s = _parts.rbegin()->second->range().to();
    }
    return s;
}

size_t
Domain::byteSize() const
{
    return byteSize(LockGuard(_lock));
}

size_t
Domain::byteSize(const LockGuard & guard) const
{
    (void) guard;
    assert(guard.locks(_lock));
    size_t size = 0;
    for (const auto &entry : _parts) {
        const DomainPart &part = *entry.second;
        size += part.byteSize();
    }
    return size;
}

SerialNum
Domain::getSynced() const
{
    SerialNum s(0);
    LockGuard guard(_lock);
    if (_parts.empty()) {
        return s;
    }
    DomainPartList::const_iterator it(_parts.end());
    --it;
    s = it->second->getSynced();
    if (s == 0 && it != _parts.begin()) {
        --it;
        s = it->second->getSynced();
    }
    return s;
}

void
Domain::triggerSyncNow()
{
    MonitorGuard guard(_syncMonitor);
    if (!_pendingSync) {
        _pendingSync = true;
        _commitExecutor.sync();
        DomainPart::SP dp(_parts.rbegin()->second);
        _sessionExecutor.execute(Sync::UP(new Sync(_syncMonitor, dp, _pendingSync)));
    }
}

DomainPart::SP Domain::findPart(SerialNum s)
{
    LockGuard guard(_lock);
    DomainPartList::iterator it(_parts.upper_bound(s));
    if (!_parts.empty() && it != _parts.begin()) {
        DomainPartList::iterator prev(it);
        --prev;
        if (prev->second->range().to() > s) {
            return prev->second;
        }
    }
    if (it != _parts.end()) {
        return it->second;
    }
    return DomainPart::SP();
}

uint64_t Domain::size() const
{
    return size(LockGuard(_lock));
}

uint64_t Domain::size(const LockGuard & guard) const
{
    (void) guard;
    assert(guard.locks(_lock));
    uint64_t sz(0);
    for (const auto & part : _parts) {
        sz += part.second->size();
    }
    return sz;
}

SerialNum Domain::findOldestActiveVisit() const
{
    SerialNum oldestActive(std::numeric_limits<SerialNum>::max());
    LockGuard guard(_sessionLock);
    for (const auto & pair : _sessions) {
        Session * session(pair.second.get());
        if (!session->inSync()) {
            oldestActive = std::min(oldestActive, session->range().from());
        }
    }
    return oldestActive;
}

void Domain::cleanSessions()
{
    if ( _sessions.empty()) {
        return;
    }
    LockGuard guard(_sessionLock);
    for (SessionList::iterator it(_sessions.begin()), mt(_sessions.end()); it != mt; ) {
        Session * session(it->second.get());
        if ((!session->continous() && session->inSync())) {
            _sessions.erase(it++);
        } else if (session->finished()) {
            _sessions.erase(it++);
        } else {
            it++;
        }
    }
}

void Domain::commit(const Packet & packet)
{
    DomainPart::SP dp(_parts.rbegin()->second);
    vespalib::nbostream_longlivedbuf is(packet.getHandle().c_str(), packet.getHandle().size());
    Packet::Entry entry;
    entry.deserialize(is);
    if (dp->byteSize() > _domainPartSize) {
        triggerSyncNow();
        {
            MonitorGuard guard(_syncMonitor);
            while (_pendingSync) {
                guard.wait();
            }
        }
        dp->close();
        dp.reset(new DomainPart(_name, dir(), entry.serial(), _defaultCrcType, _fileHeaderContext, false));
        {
            LockGuard guard(_lock);
            _parts[entry.serial()] = dp;
        }
        dp = _parts.rbegin()->second;
    }
    dp->commit(entry.serial(), packet);
    cleanSessions();

    LockGuard guard(_sessionLock);
    for (auto & it : _sessions) {
        const Session::SP & session(it.second);
        if (session->continous()) {
            if (session->ok()) {
                Session::enQ(session, entry.serial(), packet);
            }
        }
    }
}

bool Domain::erase(SerialNum to)
{
    bool retval(true);
    /// Do not erase the last element
    for (DomainPartList::iterator it(_parts.begin()); (_parts.size() > 1) && (it->second.get()->range().to() < to); it = _parts.begin()) {
        DomainPart::SP dp(it->second);
        {
            LockGuard guard(_lock);
            _parts.erase(it);
        }
        retval = retval && dp->erase(to);
    }
    if (_parts.begin()->second->range().to() >= to) {
        _parts.begin()->second->erase(to);
    }
    return retval;
}

int Domain::visit(const Domain::SP & domain, SerialNum from, SerialNum to,
                  FRT_Supervisor & supervisor, FNET_Connection *conn)
{
    assert(this == domain.get());
    cleanSessions();
    SerialNumRange range(from, to);
    Session * session = new Session(_sessionId++, range, domain, supervisor, conn);
    LockGuard guard(_sessionLock);
    _sessions[session->id()] = Session::SP(session);
    return session->id();
}

int Domain::startSession(int sessionId)
{
    int retval(-1);
    LockGuard guard(_sessionLock);
    SessionList::iterator found = _sessions.find(sessionId);
    if (found != _sessions.end()) {
        if ( execute(Session::createTask(found->second)).get() == nullptr ) {
            retval = 0;
        } else {
            _sessions.erase(sessionId);
        }
    }
    return retval;
}

int Domain::closeSession(int sessionId)
{
    _commitExecutor.sync();
    int retval(-1);
    {
        LockGuard guard(_sessionLock);
        SessionList::iterator found = _sessions.find(sessionId);
        if (found != _sessions.end()) {
            retval = 1;
            _sessionExecutor.sync();
        }
    }
    if (retval == 1) {
        FastOS_Thread::Sleep(10);
        LockGuard guard(_sessionLock);
        SessionList::iterator found = _sessions.find(sessionId);
        if (found != _sessions.end()) {
            _sessions.erase(sessionId);
            retval = 0;
        } else {
            retval = 0;
        }
    }
    return retval;
}

int Domain::subscribe(const Domain::SP & domain, SerialNum from, FRT_Supervisor & supervisor, FNET_Connection *conn)
{
    assert(this == domain.get());
    cleanSessions();
    SerialNumRange range(from, end());
    Session * session = new Session(_sessionId++, range, domain, supervisor, conn, true);
    LockGuard guard(_sessionLock);
    _sessions[session->id()] = Session::SP(session);
    return session->id();
}

Domain::SerialNumList
Domain::scanDir()
{
    SerialNumList res;

    FastOS_DirectoryScan dirScan(dir().c_str());

    const char *wantPrefix = _name.c_str();
    size_t wantPrefixLen = strlen(wantPrefix);

    while (dirScan.ReadNext()) {
        const char *ename = dirScan.GetName();
        if (strcmp(ename, ".") == 0 ||
            strcmp(ename, "..") == 0)
            continue;
        if (strncmp(ename, wantPrefix, wantPrefixLen) != 0)
            continue;
        if (ename[wantPrefixLen] != '-')
            continue;
        const char *p = ename + wantPrefixLen + 1;
        uint64_t num = strtoull(p, NULL, 10);
        string checkName = make_string("%s-%016" PRIu64, _name.c_str(), num);
        if (strcmp(checkName.c_str(), ename) != 0)
            continue;
        res.push_back(static_cast<SerialNum>(num));
    }
    std::sort(res.begin(), res.end());
    return res;
}

}
<commit_msg>Wait for existing sync task to complete before scheduling a new sync task when switching to new domain part.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "domain.h"
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/closuretask.h>
#include <vespa/fastos/file.h>
#include <algorithm>

#include <vespa/log/log.h>
LOG_SETUP(".transactionlog.domain");

using vespalib::string;
using vespalib::make_string;
using vespalib::LockGuard;
using vespalib::makeTask;
using vespalib::makeClosure;
using vespalib::Monitor;
using vespalib::MonitorGuard;
using search::common::FileHeaderContext;
using std::runtime_error;

namespace search::transactionlog {

Domain::Domain(const string &domainName, const string & baseDir, Executor & commitExecutor,
               Executor & sessionExecutor, uint64_t domainPartSize, DomainPart::Crc defaultCrcType,
               const FileHeaderContext &fileHeaderContext) :
    _defaultCrcType(defaultCrcType),
    _commitExecutor(commitExecutor),
    _sessionExecutor(sessionExecutor),
    _sessionId(1),
    _syncMonitor(),
    _pendingSync(false),
    _name(domainName),
    _domainPartSize(domainPartSize),
    _parts(),
    _lock(),
    _sessionLock(),
    _sessions(),
    _baseDir(baseDir),
    _fileHeaderContext(fileHeaderContext),
    _markedDeleted(false)
{
    int retval(0);
    if ((retval = makeDirectory(_baseDir.c_str())) != 0) {
        throw runtime_error(make_string("Failed creating basedirectory %s r(%d), e(%d)", _baseDir.c_str(), retval, errno));
    }
    if ((retval = makeDirectory(dir().c_str())) != 0) {
        throw runtime_error(make_string("Failed creating domaindir %s r(%d), e(%d)", dir().c_str(), retval, errno));
    }
    SerialNumList partIdVector = scanDir();
    const int64_t lastPart = partIdVector.empty() ? 0 : partIdVector.back();
    for (const int64_t partId : partIdVector) {
        if ( partId != -1) {
            _sessionExecutor.execute(makeTask(makeClosure(this, &Domain::addPart, partId, partId == lastPart)));
        }
    }
    _sessionExecutor.sync();
    if (_parts.empty() || _parts.crbegin()->second->isClosed()) {
        _parts[lastPart].reset(new DomainPart(_name, dir(), lastPart, _defaultCrcType, _fileHeaderContext, false));
    }
}

void Domain::addPart(int64_t partId, bool isLastPart) {
    DomainPart::SP dp(new DomainPart(_name, dir(), partId, _defaultCrcType, _fileHeaderContext, isLastPart));
    if (dp->size() == 0) {
        // Only last domain part is allowed to be truncated down to
        // empty size.
        assert(isLastPart);
        dp->erase(dp->range().to() + 1);
    } else {
        {
            LockGuard guard(_lock);
            _parts[partId] = dp;
        }
        if (! isLastPart) {
            dp->close();
        }
    }
}

class Sync : public vespalib::Executor::Task
{
public:
    Sync(Monitor &syncMonitor, const DomainPart::SP &dp, bool &pendingSync) :
        _syncMonitor(syncMonitor),
        _dp(dp),
        _pendingSync(pendingSync)
    { }
private:
    void run() override {
        _dp->sync();
        MonitorGuard guard(_syncMonitor);
        _pendingSync = false;
        guard.broadcast();
    }

    Monitor           & _syncMonitor;
    DomainPart::SP      _dp;
    bool              & _pendingSync;
};

Domain::~Domain() { }

DomainInfo
Domain::getDomainInfo() const
{
    LockGuard guard(_lock);
    DomainInfo info(SerialNumRange(begin(guard), end(guard)), size(guard), byteSize(guard));
    for (const auto &entry: _parts) {
        const DomainPart &part = *entry.second;
        info.parts.emplace_back(PartInfo(part.range(), part.size(), part.byteSize(), part.fileName()));
    }
    return info;
}

SerialNum
Domain::begin() const
{
    return begin(LockGuard(_lock));
}

SerialNum
Domain::begin(const LockGuard & guard) const
{
    (void) guard;
    assert(guard.locks(_lock));
    SerialNum s(0);
    if ( ! _parts.empty() ) {
        s = _parts.begin()->second->range().from();
    }
    return s;
}

SerialNum
Domain::end() const
{
    return end(LockGuard(_lock));
}

SerialNum
Domain::end(const LockGuard & guard) const
{
    (void) guard;
    assert(guard.locks(_lock));
    SerialNum s(0);
    if ( ! _parts.empty() ) {
        s = _parts.rbegin()->second->range().to();
    }
    return s;
}

size_t
Domain::byteSize() const
{
    return byteSize(LockGuard(_lock));
}

size_t
Domain::byteSize(const LockGuard & guard) const
{
    (void) guard;
    assert(guard.locks(_lock));
    size_t size = 0;
    for (const auto &entry : _parts) {
        const DomainPart &part = *entry.second;
        size += part.byteSize();
    }
    return size;
}

SerialNum
Domain::getSynced() const
{
    SerialNum s(0);
    LockGuard guard(_lock);
    if (_parts.empty()) {
        return s;
    }
    DomainPartList::const_iterator it(_parts.end());
    --it;
    s = it->second->getSynced();
    if (s == 0 && it != _parts.begin()) {
        --it;
        s = it->second->getSynced();
    }
    return s;
}

void
Domain::triggerSyncNow()
{
    MonitorGuard guard(_syncMonitor);
    if (!_pendingSync) {
        _pendingSync = true;
        _commitExecutor.sync();
        DomainPart::SP dp(_parts.rbegin()->second);
        _sessionExecutor.execute(Sync::UP(new Sync(_syncMonitor, dp, _pendingSync)));
    }
}

DomainPart::SP Domain::findPart(SerialNum s)
{
    LockGuard guard(_lock);
    DomainPartList::iterator it(_parts.upper_bound(s));
    if (!_parts.empty() && it != _parts.begin()) {
        DomainPartList::iterator prev(it);
        --prev;
        if (prev->second->range().to() > s) {
            return prev->second;
        }
    }
    if (it != _parts.end()) {
        return it->second;
    }
    return DomainPart::SP();
}

uint64_t Domain::size() const
{
    return size(LockGuard(_lock));
}

uint64_t Domain::size(const LockGuard & guard) const
{
    (void) guard;
    assert(guard.locks(_lock));
    uint64_t sz(0);
    for (const auto & part : _parts) {
        sz += part.second->size();
    }
    return sz;
}

SerialNum Domain::findOldestActiveVisit() const
{
    SerialNum oldestActive(std::numeric_limits<SerialNum>::max());
    LockGuard guard(_sessionLock);
    for (const auto & pair : _sessions) {
        Session * session(pair.second.get());
        if (!session->inSync()) {
            oldestActive = std::min(oldestActive, session->range().from());
        }
    }
    return oldestActive;
}

void Domain::cleanSessions()
{
    if ( _sessions.empty()) {
        return;
    }
    LockGuard guard(_sessionLock);
    for (SessionList::iterator it(_sessions.begin()), mt(_sessions.end()); it != mt; ) {
        Session * session(it->second.get());
        if ((!session->continous() && session->inSync())) {
            _sessions.erase(it++);
        } else if (session->finished()) {
            _sessions.erase(it++);
        } else {
            it++;
        }
    }
}

namespace {

void waitPendingSync(vespalib::Monitor &syncMonitor, bool &pendingSync)
{
    MonitorGuard guard(syncMonitor);
    while (pendingSync) {
        guard.wait();
    }
}

}

void Domain::commit(const Packet & packet)
{
    DomainPart::SP dp(_parts.rbegin()->second);
    vespalib::nbostream_longlivedbuf is(packet.getHandle().c_str(), packet.getHandle().size());
    Packet::Entry entry;
    entry.deserialize(is);
    if (dp->byteSize() > _domainPartSize) {
        waitPendingSync(_syncMonitor, _pendingSync);
        triggerSyncNow();
        waitPendingSync(_syncMonitor, _pendingSync);
        dp->close();
        dp.reset(new DomainPart(_name, dir(), entry.serial(), _defaultCrcType, _fileHeaderContext, false));
        {
            LockGuard guard(_lock);
            _parts[entry.serial()] = dp;
        }
        dp = _parts.rbegin()->second;
    }
    dp->commit(entry.serial(), packet);
    cleanSessions();

    LockGuard guard(_sessionLock);
    for (auto & it : _sessions) {
        const Session::SP & session(it.second);
        if (session->continous()) {
            if (session->ok()) {
                Session::enQ(session, entry.serial(), packet);
            }
        }
    }
}

bool Domain::erase(SerialNum to)
{
    bool retval(true);
    /// Do not erase the last element
    for (DomainPartList::iterator it(_parts.begin()); (_parts.size() > 1) && (it->second.get()->range().to() < to); it = _parts.begin()) {
        DomainPart::SP dp(it->second);
        {
            LockGuard guard(_lock);
            _parts.erase(it);
        }
        retval = retval && dp->erase(to);
    }
    if (_parts.begin()->second->range().to() >= to) {
        _parts.begin()->second->erase(to);
    }
    return retval;
}

int Domain::visit(const Domain::SP & domain, SerialNum from, SerialNum to,
                  FRT_Supervisor & supervisor, FNET_Connection *conn)
{
    assert(this == domain.get());
    cleanSessions();
    SerialNumRange range(from, to);
    Session * session = new Session(_sessionId++, range, domain, supervisor, conn);
    LockGuard guard(_sessionLock);
    _sessions[session->id()] = Session::SP(session);
    return session->id();
}

int Domain::startSession(int sessionId)
{
    int retval(-1);
    LockGuard guard(_sessionLock);
    SessionList::iterator found = _sessions.find(sessionId);
    if (found != _sessions.end()) {
        if ( execute(Session::createTask(found->second)).get() == nullptr ) {
            retval = 0;
        } else {
            _sessions.erase(sessionId);
        }
    }
    return retval;
}

int Domain::closeSession(int sessionId)
{
    _commitExecutor.sync();
    int retval(-1);
    {
        LockGuard guard(_sessionLock);
        SessionList::iterator found = _sessions.find(sessionId);
        if (found != _sessions.end()) {
            retval = 1;
            _sessionExecutor.sync();
        }
    }
    if (retval == 1) {
        FastOS_Thread::Sleep(10);
        LockGuard guard(_sessionLock);
        SessionList::iterator found = _sessions.find(sessionId);
        if (found != _sessions.end()) {
            _sessions.erase(sessionId);
            retval = 0;
        } else {
            retval = 0;
        }
    }
    return retval;
}

int Domain::subscribe(const Domain::SP & domain, SerialNum from, FRT_Supervisor & supervisor, FNET_Connection *conn)
{
    assert(this == domain.get());
    cleanSessions();
    SerialNumRange range(from, end());
    Session * session = new Session(_sessionId++, range, domain, supervisor, conn, true);
    LockGuard guard(_sessionLock);
    _sessions[session->id()] = Session::SP(session);
    return session->id();
}

Domain::SerialNumList
Domain::scanDir()
{
    SerialNumList res;

    FastOS_DirectoryScan dirScan(dir().c_str());

    const char *wantPrefix = _name.c_str();
    size_t wantPrefixLen = strlen(wantPrefix);

    while (dirScan.ReadNext()) {
        const char *ename = dirScan.GetName();
        if (strcmp(ename, ".") == 0 ||
            strcmp(ename, "..") == 0)
            continue;
        if (strncmp(ename, wantPrefix, wantPrefixLen) != 0)
            continue;
        if (ename[wantPrefixLen] != '-')
            continue;
        const char *p = ename + wantPrefixLen + 1;
        uint64_t num = strtoull(p, NULL, 10);
        string checkName = make_string("%s-%016" PRIu64, _name.c_str(), num);
        if (strcmp(checkName.c_str(), ename) != 0)
            continue;
        res.push_back(static_cast<SerialNum>(num));
    }
    std::sort(res.begin(), res.end());
    return res;
}

}
<|endoftext|>


<commit_before>#include "message.hpp"

#include "common.hpp"

#include <SipHash_2_4.h>
#include <string.h>

static uint8_t *computeHash(const uint8_t *key, uint16_t sender,
                            uint16_t reciever, unsigned char type,
                            const char *message, uint8_t message_len) {
  sipHash.initFromRAM(key);

  sipHash.updateHash(sender & 0xff);
  sipHash.updateHash((sender >> 8) & 0xff);

  sipHash.updateHash(reciever & 0xff);
  sipHash.updateHash((reciever >> 8) & 0xff);

  sipHash.updateHash(type);

  for (int i = 0; i < message_len; i++) {
    sipHash.updateHash((byte)message[i]);
  }
  sipHash.finish();
  return sipHash.result;
}

void Message::init(session_t session, counter_t counter) {
  _pos = 1;
  _len =
      PAYLOAD_LEN + sizeof(msg_size_t) + sizeof(session_t) + sizeof(counter_t);

  setShort(session);
  setShort(counter);
}

msg_size_t Message::finalize(const uint8_t *key, node_t from_node,
                             node_t to_node, type_t type) {

  uint8_t *hash = computeHash(key, from_node, to_node, type, _buffer, _pos);
  memcpy(_buffer + _pos, hash, HASH_LEN);

  _buffer[0] = _pos;

  _len = _pos + HASH_LEN;

  return _len;
}

bool Message::verify(const uint8_t *key, node_t from, node_t to, type_t type,
                     uint16_t len) {
  if (_len < SESSION_LEN + sizeof(counter_t) + HASH_LEN + sizeof(msg_size_t)) {
    DEBUG_LOG("Message too short: %d !", _len);
    return false;
  }

  if (_len != (_buffer[0] + HASH_LEN)) {
    DEBUG_LOG("bytes read does not match len: len(%d) != read(%d)", _buffer[0],
              len);
    return false;
  }

  _len = _buffer[0];
  _pos = 1;

  uint8_t *hash = computeHash(key, from, to, type, _buffer, _len);

  uint8_t *ref_hash = (uint8_t *)_buffer + _len;
  for (uint8_t i = 0; i < HASH_LEN; i++) {
    if (hash[i] != ref_hash[i]) {
      DEBUG_LOG("Byte %d of hash does not match: hash(%x) != ref(%x)", hash[i],
                ref_hash[i]);
      return false;
    }
  }

  return true;
}
<commit_msg>Unify endianess<commit_after>#include "message.hpp"

#include "common.hpp"

#include <SipHash_2_4.h>
#include <string.h>

static uint8_t *computeHash(const uint8_t *key, uint16_t sender,
                            uint16_t reciever, unsigned char type,
                            const char *message, uint8_t message_len) {
  sipHash.initFromRAM(key);

  sipHash.updateHash((sender >> 8) & 0xff);
  sipHash.updateHash(sender & 0xff);

  sipHash.updateHash((reciever >> 8) & 0xff);
  sipHash.updateHash(reciever & 0xff);

  sipHash.updateHash(type);

  for (int i = 0; i < message_len; i++) {
    sipHash.updateHash((byte)message[i]);
  }
  sipHash.finish();
  return sipHash.result;
}

void Message::init(session_t session, counter_t counter) {
  _pos = 1;
  _len =
      PAYLOAD_LEN + sizeof(msg_size_t) + sizeof(session_t) + sizeof(counter_t);

  setShort(session);
  setShort(counter);
}

msg_size_t Message::finalize(const uint8_t *key, node_t from_node,
                             node_t to_node, type_t type) {

  uint8_t *hash = computeHash(key, from_node, to_node, type, _buffer, _pos);
  memcpy(_buffer + _pos, hash, HASH_LEN);

  _buffer[0] = _pos;

  _len = _pos + HASH_LEN;

  return _len;
}

bool Message::verify(const uint8_t *key, node_t from, node_t to, type_t type,
                     uint16_t len) {
  if (_len < SESSION_LEN + sizeof(counter_t) + HASH_LEN + sizeof(msg_size_t)) {
    DEBUG_LOG("Message too short: %d !", _len);
    return false;
  }

  if (_len != (_buffer[0] + HASH_LEN)) {
    DEBUG_LOG("bytes read does not match len: len(%d) != read(%d)", _buffer[0],
              len);
    return false;
  }

  _len = _buffer[0];
  _pos = 1;

  uint8_t *hash = computeHash(key, from, to, type, _buffer, _len);

  uint8_t *ref_hash = (uint8_t *)_buffer + _len;
  for (uint8_t i = 0; i < HASH_LEN; i++) {
    if (hash[i] != ref_hash[i]) {
      DEBUG_LOG("Byte %d of hash does not match: hash(%x) != ref(%x)", hash[i],
                ref_hash[i]);
      return false;
    }
  }

  return true;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <string>

#include "Types.hpp"
#include "SemanticalException.hpp"

using namespace eddic;

Type::Type(BaseType base) : type(base), array(false), m_size(0) {}
Type::Type(BaseType base, unsigned int size) : type(base), array(true), m_size(size) {}

BaseType Type::base() const {
    return type;
}

bool Type::isArray() const {
    return array;
}

unsigned int Type::size() const {
    return m_size;
}

bool eddic::operator==(const Type& lhs, const Type& rhs){
    return lhs.type == rhs.type &&
           lhs.array == rhs.array &&
           lhs.m_size == rhs.m_size;
}

bool eddic::operator!=(const Type& lhs, const Type& rhs){
    return !(lhs == rhs);
}

const int typeSizes[(int) BaseType::COUNT] = { 8, 4, 0 };

int eddic::size(BaseType type){
    return typeSizes[(unsigned int) type];
}

int eddic::size(Type type){
    if(type.isArray()){
        return size(type.base()) * type.size() + size(BaseType::INT);
    } else {
        return size(type.base());
    }
}

bool eddic::isType(const std::string& type){
    return type == "int" || type == "void" || type == "string";
}

BaseType eddic::stringToBaseType(const std::string& type){
    if (type == "int") {
        return BaseType::INT;
    } else if (type == "string"){
        return BaseType::STRING;
    } else if(type == "void") {
        return BaseType::VOID;
    }

    throw SemanticalException("Invalid type");
}

Type eddic::stringToType(const std::string& type){
    if (type == "int") {
        return Type(BaseType::INT);
    } else if (type == "string"){
        return Type(BaseType::STRING);
    } else if(type == "void") {
        return Type(BaseType::VOID);
    }

    throw SemanticalException("Invalid type");
}
<commit_msg>Allow conversion of string types to Type objects<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <string>

#include "Types.hpp"
#include "SemanticalException.hpp"

using namespace eddic;

Type::Type(BaseType base) : type(base), array(false), m_size(0) {}
Type::Type(BaseType base, unsigned int size) : type(base), array(true), m_size(size) {}

BaseType Type::base() const {
    return type;
}

bool Type::isArray() const {
    return array;
}

unsigned int Type::size() const {
    return m_size;
}

bool eddic::operator==(const Type& lhs, const Type& rhs){
    return lhs.type == rhs.type &&
           lhs.array == rhs.array &&
           lhs.m_size == rhs.m_size;
}

bool eddic::operator!=(const Type& lhs, const Type& rhs){
    return !(lhs == rhs);
}

const int typeSizes[(int) BaseType::COUNT] = { 8, 4, 0 };

int eddic::size(BaseType type){
    return typeSizes[(unsigned int) type];
}

int eddic::size(Type type){
    if(type.isArray()){
        return size(type.base()) * type.size() + size(BaseType::INT);
    } else {
        return size(type.base());
    }
}

bool eddic::isType(const std::string& type){
    return type == "int" || type == "void" || type == "string";
}

BaseType eddic::stringToBaseType(const std::string& type){
    if (type == "int") {
        return BaseType::INT;
    } else if (type == "string"){
        return BaseType::STRING;
    } else if(type == "void") {
        return BaseType::VOID;
    }

    throw SemanticalException("Invalid type");
}

Type eddic::stringToType(const std::string& type){
    if (type == "int") {
        return Type(BaseType::INT);
    } else if (type == "string"){
        return Type(BaseType::STRING);
    } else if(type == "int[]") {
        return Type(BaseType::INT, 0);//Use a more proper way to set that it's an array type
    } else if(type == "string[]") {
        return Type(BaseType::STRING, 0);//Use a more proper way to set that it's an array type
    } else if(type == "void") {
        return Type(BaseType::VOID);
    }

    throw SemanticalException("Invalid type");
}
<|endoftext|>


<commit_before>#include "backuplistwidget.h"
#include "backuplistitem.h"
#include "debug.h"

#include <QDropEvent>
#include <QMimeData>
#include <QFileInfo>
#include <QSettings>

BackupListWidget::BackupListWidget(QWidget *parent):
    QListWidget(parent)
{
    QSettings settings;
    QStringList urls = settings.value("app/backup_list").toStringList();
    if(!urls.isEmpty())
    {
        QList<QUrl> urllist;
        foreach (QString url, urls)
            urllist << QUrl::fromUserInput(url);
        if(!urllist.isEmpty())
            QMetaObject::invokeMethod(this, "addItemsWithUrls"
                                      , Qt::QueuedConnection, Q_ARG(QList<QUrl>, urllist));
    }
}

BackupListWidget::~BackupListWidget()
{
    QSettings settings;
    QStringList urls;
    for(int i = 0; i < this->count(); ++i)
    {
        BackupListItem *backupItem = dynamic_cast<BackupListItem*>(item(i));
        urls << backupItem->url().toString(QUrl::FullyEncoded);
    }
    settings.setValue("app/backup_list", urls);
    settings.sync();
    clear();
}

void BackupListWidget::addItemWithUrl(QUrl url)
{
    if(!url.isEmpty())
    {
        QString fileUrl = url.toLocalFile();
        if(fileUrl.isEmpty())
            return;
        QFileInfo file(fileUrl);
        if(!file.exists())
            return;
        BackupListItem *item = new BackupListItem(url);
        connect(item, SIGNAL(requestDelete()), this, SLOT(removeItems()));
        connect(item, SIGNAL(requestUpdate()), this, SLOT(recomputeListTotals()));
        this->insertItem(this->count(), item);
        this->setItemWidget(item, item->widget());
    }
}

void BackupListWidget::addItemsWithUrls(QList<QUrl> urls)
{
    foreach (QUrl url, urls)
        addItemWithUrl(url);
    recomputeListTotals();
}

void BackupListWidget::removeItems()
{
    if(this->selectedItems().count() == 0)
    {
        // attempt to remove the sender
        BackupListItem* backupItem = qobject_cast<BackupListItem*>(sender());
        if(backupItem)
        {
            QListWidgetItem *item = this->takeItem(this->row(backupItem));
            if(item)
                delete item;
        }
    }
    else
    {
        foreach (QListWidgetItem *item, this->selectedItems())
        {
            if(item->isSelected())
            {
                QListWidgetItem *takenItem = this->takeItem(this->row(item));
                if(takenItem)
                    delete takenItem;
            }
        }
    }
    recomputeListTotals();
}

void BackupListWidget::recomputeListTotals()
{
    qint64 count = 0;
    qint64 size = 0;
    for(int i = 0; i < this->count(); ++i)
    {
        BackupListItem *backupItem = dynamic_cast<BackupListItem*>(item(i));
        if(backupItem && (backupItem->count() != 0))
        {
            count += backupItem->count();
            size  += backupItem->size();
        }
    }
    emit itemTotals(count, size);
}

void BackupListWidget::dragMoveEvent( QDragMoveEvent* event )
{
    if ( !event->mimeData()->hasUrls() )
    {
        event->ignore();
        return;
    }
    event->accept();
}

void BackupListWidget::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasUrls())
        event->acceptProposedAction();
}

void BackupListWidget::dropEvent(QDropEvent *event)
{
    QList<QUrl> urls = event->mimeData()->urls();
    if (!urls.isEmpty())
        addItemsWithUrls(urls);

    event->acceptProposedAction();
}

void BackupListWidget::keyReleaseEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Delete:
    case Qt::Key_Backspace:
        removeItems();
        break;
    case Qt::Key_Escape:
        if(this->selectedItems().count() != 0)
            clearSelection();
        else
            QListWidget::keyReleaseEvent(event);
        break;
    default:
        QListWidget::keyReleaseEvent(event);
    }
}

<commit_msg>Browse the url using the desktop services when an item in the backup list is activated.<commit_after>#include "backuplistwidget.h"
#include "backuplistitem.h"
#include "debug.h"

#include <QDropEvent>
#include <QMimeData>
#include <QFileInfo>
#include <QSettings>

BackupListWidget::BackupListWidget(QWidget *parent):
    QListWidget(parent)
{
    QSettings settings;
    QStringList urls = settings.value("app/backup_list").toStringList();
    if(!urls.isEmpty())
    {
        QList<QUrl> urllist;
        foreach (QString url, urls)
            urllist << QUrl::fromUserInput(url);
        if(!urllist.isEmpty())
            QMetaObject::invokeMethod(this, "addItemsWithUrls"
                                      , Qt::QueuedConnection, Q_ARG(QList<QUrl>, urllist));
    }
    connect(this, &QListWidget::itemActivated,
            [=](QListWidgetItem *item)
            {
                static_cast<BackupListItem*>(item)->browseUrl();
            });
}

BackupListWidget::~BackupListWidget()
{
    QSettings settings;
    QStringList urls;
    for(int i = 0; i < this->count(); ++i)
    {
        BackupListItem *backupItem = dynamic_cast<BackupListItem*>(item(i));
        urls << backupItem->url().toString(QUrl::FullyEncoded);
    }
    settings.setValue("app/backup_list", urls);
    settings.sync();
    clear();
}

void BackupListWidget::addItemWithUrl(QUrl url)
{
    if(!url.isEmpty())
    {
        QString fileUrl = url.toLocalFile();
        if(fileUrl.isEmpty())
            return;
        QFileInfo file(fileUrl);
        if(!file.exists())
            return;
        BackupListItem *item = new BackupListItem(url);
        connect(item, SIGNAL(requestDelete()), this, SLOT(removeItems()));
        connect(item, SIGNAL(requestUpdate()), this, SLOT(recomputeListTotals()));
        this->insertItem(this->count(), item);
        this->setItemWidget(item, item->widget());
    }
}

void BackupListWidget::addItemsWithUrls(QList<QUrl> urls)
{
    foreach (QUrl url, urls)
        addItemWithUrl(url);
    recomputeListTotals();
}

void BackupListWidget::removeItems()
{
    if(this->selectedItems().count() == 0)
    {
        // attempt to remove the sender
        BackupListItem* backupItem = qobject_cast<BackupListItem*>(sender());
        if(backupItem)
        {
            QListWidgetItem *item = this->takeItem(this->row(backupItem));
            if(item)
                delete item;
        }
    }
    else
    {
        foreach (QListWidgetItem *item, this->selectedItems())
        {
            if(item->isSelected())
            {
                QListWidgetItem *takenItem = this->takeItem(this->row(item));
                if(takenItem)
                    delete takenItem;
            }
        }
    }
    recomputeListTotals();
}

void BackupListWidget::recomputeListTotals()
{
    qint64 count = 0;
    qint64 size = 0;
    for(int i = 0; i < this->count(); ++i)
    {
        BackupListItem *backupItem = dynamic_cast<BackupListItem*>(item(i));
        if(backupItem && (backupItem->count() != 0))
        {
            count += backupItem->count();
            size  += backupItem->size();
        }
    }
    emit itemTotals(count, size);
}

void BackupListWidget::dragMoveEvent( QDragMoveEvent* event )
{
    if ( !event->mimeData()->hasUrls() )
    {
        event->ignore();
        return;
    }
    event->accept();
}

void BackupListWidget::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasUrls())
        event->acceptProposedAction();
}

void BackupListWidget::dropEvent(QDropEvent *event)
{
    QList<QUrl> urls = event->mimeData()->urls();
    if (!urls.isEmpty())
        addItemsWithUrls(urls);

    event->acceptProposedAction();
}

void BackupListWidget::keyReleaseEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Delete:
    case Qt::Key_Backspace:
        removeItems();
        break;
    case Qt::Key_Escape:
        if(this->selectedItems().count() != 0)
            clearSelection();
        else
            QListWidget::keyReleaseEvent(event);
        break;
    default:
        QListWidget::keyReleaseEvent(event);
    }
}

<|endoftext|>


<commit_before>/*
 *  Copyright 2007-2013 The OpenMx Project
 *
 *  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 "R.h"
#include <Rinternals.h>
#include <Rdefines.h>
#include <R_ext/Rdynload.h>
#include <R_ext/BLAS.h>
#include <R_ext/Lapack.h>
#include <sys/types.h>

#include "omxDefines.h"
#include "omxState.h"

void cacheFreeVarDependencies(omxState* os)
{
	size_t numMats = os->matrixList.size();

	os->markMatrices.clear();
	os->markMatrices.resize(numMats + os->numAlgs, 0);

	for(int freeVarIndex = 0; freeVarIndex < os->numFreeParams; freeVarIndex++) {
		omxFreeVar* freeVar = os->freeVarList + freeVarIndex;
		int *deps   = freeVar->deps;
		int numDeps = freeVar->numDeps;
		for (int index = 0; index < numDeps; index++) {
			os->markMatrices[deps[index] + numMats] = 1;
		}
	}

}

void markFreeVarDependenciesHelper(omxState* os, int varNumber) {

	int numDeps = os->freeVarList[varNumber].numDeps;
	int *deps = os->freeVarList[varNumber].deps;

	omxMatrix** algebraList = os->algebraList;

	for (int i = 0; i < numDeps; i++) {
		int value = deps[i];

		if(value < 0) {
			omxMarkDirty(os->matrixList[~value]);
		} else {
			omxMarkDirty(algebraList[value]);
		}
	}

}

void markFreeVarDependencies(omxState* os, int varNumber) {

	int numChildren = os->numChildren;

	markFreeVarDependenciesHelper(os, varNumber);

	for(int i = 0; i < numChildren; i++) {
		markFreeVarDependencies(os->childList[i], varNumber);
	}
}

static void handleFreeVarListHelper(omxState* os, double* x, int numVars, omxState *topState) {

	int numChildren = os->numChildren;

	if(OMX_DEBUG && os->parentState == NULL) {
		Rprintf("Processing Free Parameter Estimates.\n");
		Rprintf("Number of free parameters is %d.\n", numVars);
	}

	if(numVars == 0) return;

	omxFreeVar* freeVarList = os->freeVarList;
	omxMatrix** algebraList = os->algebraList;
	size_t numMats = os->matrixList.size();
	int numAlgs = os->numAlgs;

	os->computeCount++;

	if(OMX_VERBOSE && os->parentState == NULL) {
		Rprintf("--------------------------\n");
		Rprintf("Call: %d.%d (%d)\n", os->majorIteration, os->minorIteration, os->computeCount);
		Rprintf("Estimates: [");
		for(int k = 0; k < numVars; k++) {
			Rprintf(" %f", x[k]);
		}
		Rprintf("] \n");
		Rprintf("--------------------------\n");
	}

	/* Fill in Free Var Estimates */
	for(int k = 0; k < numVars; k++) {
		omxFreeVar* freeVar = freeVarList + k;
		// if(OMX_DEBUG) { Rprintf("%d: %f - %d\n", k,  x[k], freeVarList[k].numLocations); }
		for(size_t l = 0; l < freeVar->locations.size(); l++) {
			omxFreeVarLocation *loc = &freeVar->locations[l];
			omxMatrix *matrix = os->matrixList[loc->matrix];
			int row = loc->row;
			int col = loc->col;
			omxSetMatrixElement(matrix, row, col, x[k]);
			if(OMX_DEBUG && os->parentState == NULL) {
				Rprintf("Setting location (%d, %d) of matrix %d to value %f for var %d\n",
					row, col, loc->matrix, x[k], k);
			}
		}
	}

	for(size_t i = 0; i < numMats; i++) {
		if (topState->markMatrices[i]) {
			int offset = ~(i - numMats);
			omxMarkDirty(os->matrixList[offset]);
		}
	}

	for(int i = 0; i < numAlgs; i++) {
		if (topState->markMatrices[i + numMats]) {
			omxMarkDirty(algebraList[i]);
		}
	}

	for(int i = 0; i < numChildren; i++) {
		handleFreeVarListHelper(os->childList[i], x, numVars, topState);
	}
}

/* Sub Free Vars Into Appropriate Slots */
void handleFreeVarList(omxState* os, double* x, int numVars) {
	handleFreeVarListHelper(os, x, numVars, os);
}

/* get the list element named str, or return NULL */
SEXP getListElement(SEXP list, const char *str) {
/* Attribution: modified from the code given in Writing R Extensions */
	SEXP elmt = R_NilValue, names = getAttrib(list, R_NamesSymbol);
	int i;
	for (i = 0; i < length(list); i++)
		if(strcmp(CHAR(STRING_ELT(names, i)), str) == 0) {
			elmt = VECTOR_ELT(list, i);
			break;
		}
	return elmt;
}

SEXP getVar(SEXP str, SEXP env) {
/* Attribution: modified from the code given in Writing R Extensions */
   SEXP ans;
   if(!isString(str) || length(str) != 1)
        error("getVar: variable name is not a single string");
   if(!isEnvironment(env))
	error("getVar: env should be an environment");
   ans = findVar(install(CHAR(STRING_ELT(str, 0))), env);
   return(ans);
}

<commit_msg>Fix compile error after big revert<commit_after>/*
 *  Copyright 2007-2013 The OpenMx Project
 *
 *  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 "R.h"
#include <Rinternals.h>
#include <Rdefines.h>
#include <R_ext/Rdynload.h>
#include <R_ext/BLAS.h>
#include <R_ext/Lapack.h>
#include <sys/types.h>

#include "omxDefines.h"
#include "omxState.h"

void cacheFreeVarDependencies(omxState* os)
{
	size_t numMats = os->matrixList.size();

	os->markMatrices.clear();
	os->markMatrices.resize(numMats + os->numAlgs, 0);

	for(int freeVarIndex = 0; freeVarIndex < os->numFreeParams; freeVarIndex++) {
		omxFreeVar* freeVar = os->freeVarList + freeVarIndex;
		int *deps   = freeVar->deps;
		int numDeps = freeVar->numDeps;
		for (int index = 0; index < numDeps; index++) {
			os->markMatrices[deps[index] + numMats] = 1;
		}
	}

}

void markFreeVarDependenciesHelper(omxState* os, int varNumber) {

	int numDeps = os->freeVarList[varNumber].numDeps;
	int *deps = os->freeVarList[varNumber].deps;

	omxMatrix** algebraList = os->algebraList;

	for (int i = 0; i < numDeps; i++) {
		int value = deps[i];

		if(value < 0) {
			omxMarkDirty(os->matrixList[~value]);
		} else {
			omxMarkDirty(algebraList[value]);
		}
	}

}

void markFreeVarDependencies(omxState* os, int varNumber) {

	int numChildren = os->numChildren;

	markFreeVarDependenciesHelper(os, varNumber);

	for(int i = 0; i < numChildren; i++) {
		markFreeVarDependencies(os->childList[i], varNumber);
	}
}

static void handleFreeVarListHelper(omxState* os, double* x, int numVars, omxState *topState) {

	int numChildren = os->numChildren;

	if(OMX_DEBUG && os->parentState == NULL) {
		Rprintf("Processing Free Parameter Estimates.\n");
		Rprintf("Number of free parameters is %d.\n", numVars);
	}

	if(numVars == 0) return;

	omxFreeVar* freeVarList = os->freeVarList;
	omxMatrix** algebraList = os->algebraList;
	size_t numMats = os->matrixList.size();
	int numAlgs = os->numAlgs;

	os->computeCount++;

	if(OMX_VERBOSE && os->parentState == NULL) {
		Rprintf("--------------------------\n");
		Rprintf("Call: %d.%d (%d)\n", os->majorIteration, os->minorIteration, os->computeCount);
		Rprintf("Estimates: [");
		for(int k = 0; k < numVars; k++) {
			Rprintf(" %f", x[k]);
		}
		Rprintf("] \n");
		Rprintf("--------------------------\n");
	}

	/* Fill in Free Var Estimates */
	for(int k = 0; k < numVars; k++) {
		omxFreeVar* freeVar = freeVarList + k;
		// if(OMX_DEBUG) { Rprintf("%d: %f - %d\n", k,  x[k], freeVarList[k].numLocations); }
		for(size_t l = 0; l < freeVar->locations.size(); l++) {
			omxFreeVarLocation *loc = &freeVar->locations[l];
			omxMatrix *matrix = os->matrixList[loc->matrix];
			int row = loc->row;
			int col = loc->col;
			omxSetMatrixElement(matrix, row, col, x[k]);
			if(OMX_DEBUG && os->parentState == NULL) {
				Rprintf("Setting location (%d, %d) of matrix %d to value %f for var %d\n",
					row, col, loc->matrix, x[k], k);
			}
		}
	}

	for(size_t i = 0; i < numMats; i++) {
		if (topState->markMatrices[i]) {
			int offset = ~(i - numMats);
			omxMarkDirty(os->matrixList[offset]);
		}
	}

	for(int i = 0; i < numAlgs; i++) {
		if (os->markMatrices[i + numMats]) {
			omxMarkDirty(algebraList[i]);
		}
	}

	for(int i = 0; i < numChildren; i++) {
		handleFreeVarListHelper(os->childList[i], x, numVars, topState);
	}
}

/* Sub Free Vars Into Appropriate Slots */
void handleFreeVarList(omxState* os, double* x, int numVars) {
	handleFreeVarListHelper(os, x, numVars, os);
}

/* get the list element named str, or return NULL */
SEXP getListElement(SEXP list, const char *str) {
/* Attribution: modified from the code given in Writing R Extensions */
	SEXP elmt = R_NilValue, names = getAttrib(list, R_NamesSymbol);
	int i;
	for (i = 0; i < length(list); i++)
		if(strcmp(CHAR(STRING_ELT(names, i)), str) == 0) {
			elmt = VECTOR_ELT(list, i);
			break;
		}
	return elmt;
}

SEXP getVar(SEXP str, SEXP env) {
/* Attribution: modified from the code given in Writing R Extensions */
   SEXP ans;
   if(!isString(str) || length(str) != 1)
        error("getVar: variable name is not a single string");
   if(!isEnvironment(env))
	error("getVar: env should be an environment");
   ans = findVar(install(CHAR(STRING_ELT(str, 0))), env);
   return(ans);
}

<|endoftext|>


<commit_before><commit_msg>removed redundant code in preferences.cpp<commit_after><|endoftext|>


<commit_before>#include "resources.h"

#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dirent.h>
#endif
#include <cstdio>
#include <filesystem>
#include <SDL.h>

#if defined(ANDROID)
#include <android/native_activity.h>
#include <android/asset_manager.h>
#endif

PVector<ResourceProvider> resourceProviders;

ResourceProvider::ResourceProvider()
{
    resourceProviders.push_back(this);
}

bool ResourceProvider::searchMatch(const string name, const string searchPattern)
{
    std::vector<string> parts = searchPattern.split("*");
    int pos = 0;
    if (parts[0].length() > 0)
    {
        if (name.find(parts[0]) != 0)
            return false;
    }
    for(unsigned int n=1; n<parts.size(); n++)
    {
        int offset = name.find(parts[n], pos);
        if (offset < 0)
            return false;
        pos = offset + static_cast<int>(parts[n].length());
    }
    return pos == static_cast<int>(name.length());
}

string ResourceStream::readLine()
{
    string ret;
    char c;
    while(true)
    {
        if (read(&c, 1) < 1)
            return ret;
        if (c == '\n')
            return ret;
        ret += string(c);
    }
}

string ResourceStream::readAll()
{
    string result;
    result.resize(getSize());
    read(result.data(), result.size());
    return result;
}

class FileResourceStream : public ResourceStream
{
    SDL_RWops *io;
    size_t size = 0;
    bool open_success;
public:
    FileResourceStream(string filename)
    {
#ifndef ANDROID
        std::error_code ec;
        if(!std::filesystem::is_regular_file(filename.c_str(), ec))
        {
            //Error code "no such file or directory" thrown really often, so no trace here
            //not to spam the log
            io = nullptr;
        }
        else
            io = SDL_RWFromFile(filename.c_str(), "rb");
#else
       //Android reads from the assets bundle, so we cannot check if the file exists and is a regular file
       io = SDL_RWFromFile(filename.c_str(), "rb");
#endif
    }

    virtual ~FileResourceStream()
    {
        if (io)
            io->close(io);
    }

    bool isOpen()
    {
        return io != nullptr;
    }

    virtual size_t read(void* data, size_t size) override
    {
        return io->read(io, data, 1, size);
    }
    virtual size_t seek(size_t position) override
    {
        return io->seek(io, position, RW_SEEK_SET);
    }
    virtual size_t tell() override
    {
        return io->seek(io, 0, RW_SEEK_CUR);
    }
    virtual size_t getSize() override
    {
        if (size == 0) {
            size_t cur = tell();
            size = io->seek(io, 0, RW_SEEK_END);
            seek(cur);
        }
        return size;
    }
};

DirectoryResourceProvider::DirectoryResourceProvider(string basepath)
{
    this->basepath = basepath.rstrip("\\/");
}

P<ResourceStream> DirectoryResourceProvider::getResourceStream(string filename)
{
    P<FileResourceStream> stream = new FileResourceStream(basepath + "/" + filename);
    if (stream->isOpen())
        return stream;
    return nullptr;
}

std::vector<string> DirectoryResourceProvider::findResources(string searchPattern)
{
    std::vector<string> found_files;
#if defined(ANDROID)
    //Limitation :
    //As far as I know, Android NDK won't provide a way to list subdirectories
    //So we will only list files in the first level directory
    ANativeActivity *nactivity {sf::getNativeActivity()};

    AAssetManager *asset_manager{nullptr};
    if(nactivity)
    {
        asset_manager = nactivity->assetManager;
    }
    if(asset_manager)
    {
        int idx = searchPattern.rfind("/");
        string forced_path = basepath;
        string prefix = "";
        if (idx > -1)
        {
            prefix = searchPattern.substr(0, idx);
            forced_path += "/" + prefix;
            prefix += "/";
        }
        AAssetDir* dir = AAssetManager_openDir(asset_manager, (forced_path).c_str());
        if (dir)
        {
            const char* filename;
            while ((filename = AAssetDir_getNextFileName(dir)) != nullptr)
            {
                if (searchMatch(prefix + filename, searchPattern))
                    found_files.push_back(prefix + filename);
            }
            AAssetDir_close(dir);
        }
    }
#else
    findResources(found_files, "", searchPattern);
#endif
    return found_files;
}

void DirectoryResourceProvider::findResources(std::vector<string>& found_files, const string path, const string searchPattern)
{
#ifdef _MSC_VER
    WIN32_FIND_DATAA data;
    string search_root(basepath + "/" + path);
    if (!search_root.endswith("/"))
    {
        search_root += "/";
    }
    HANDLE handle = FindFirstFileA((search_root + "*").c_str(), &data);
    if (handle == INVALID_HANDLE_VALUE)
        return;
    do
    {
        if (data.cFileName[0] == '.')
            continue;
        string name = path + string(data.cFileName);
        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            findResources(found_files, name + "/", searchPattern);
        }
        else
        {
            if (searchMatch(name, searchPattern))
                found_files.push_back(name);
        }
    } while (FindNextFileA(handle, &data));

    FindClose(handle);
#else
    DIR* dir = opendir((basepath + "/" + path).c_str());
    if (!dir)
        return;

    struct dirent *entry;
    while ((entry = readdir(dir)) != nullptr)
    {
        if (entry->d_name[0] == '.')
            continue;
        string name = path + string(entry->d_name);
        if (searchMatch(name, searchPattern))
            found_files.push_back(name);
        findResources(found_files, path + string(entry->d_name) + "/", searchPattern);
    }
    closedir(dir);
#endif
}

P<ResourceStream> getResourceStream(string filename)
{
    foreach(ResourceProvider, rp, resourceProviders)
    {
        P<ResourceStream> stream = rp->getResourceStream(filename);
        if (stream)
            return stream;
    }
    return NULL;
}

std::vector<string> findResources(string searchPattern)
{
    std::vector<string> foundFiles;
    foreach(ResourceProvider, rp, resourceProviders)
    {
        std::vector<string> res = rp->findResources(searchPattern);
        foundFiles.insert(foundFiles.end(), res.begin(), res.end());
    }
    return foundFiles;
}
<commit_msg>Try to fix android build for resources.cpp<commit_after>#include "resources.h"

#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dirent.h>
#endif
#include <cstdio>
#include <filesystem>
#include <SDL.h>

#ifdef ANDROID
#include <SDL.h>
#include <jni.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#endif

PVector<ResourceProvider> resourceProviders;

ResourceProvider::ResourceProvider()
{
    resourceProviders.push_back(this);
}

bool ResourceProvider::searchMatch(const string name, const string searchPattern)
{
    std::vector<string> parts = searchPattern.split("*");
    int pos = 0;
    if (parts[0].length() > 0)
    {
        if (name.find(parts[0]) != 0)
            return false;
    }
    for(unsigned int n=1; n<parts.size(); n++)
    {
        int offset = name.find(parts[n], pos);
        if (offset < 0)
            return false;
        pos = offset + static_cast<int>(parts[n].length());
    }
    return pos == static_cast<int>(name.length());
}

string ResourceStream::readLine()
{
    string ret;
    char c;
    while(true)
    {
        if (read(&c, 1) < 1)
            return ret;
        if (c == '\n')
            return ret;
        ret += string(c);
    }
}

string ResourceStream::readAll()
{
    string result;
    result.resize(getSize());
    read(result.data(), result.size());
    return result;
}

class FileResourceStream : public ResourceStream
{
    SDL_RWops *io;
    size_t size = 0;
    bool open_success;
public:
    FileResourceStream(string filename)
    {
#ifndef ANDROID
        std::error_code ec;
        if(!std::filesystem::is_regular_file(filename.c_str(), ec))
        {
            //Error code "no such file or directory" thrown really often, so no trace here
            //not to spam the log
            io = nullptr;
        }
        else
            io = SDL_RWFromFile(filename.c_str(), "rb");
#else
       //Android reads from the assets bundle, so we cannot check if the file exists and is a regular file
       io = SDL_RWFromFile(filename.c_str(), "rb");
#endif
    }

    virtual ~FileResourceStream()
    {
        if (io)
            io->close(io);
    }

    bool isOpen()
    {
        return io != nullptr;
    }

    virtual size_t read(void* data, size_t size) override
    {
        return io->read(io, data, 1, size);
    }
    virtual size_t seek(size_t position) override
    {
        return io->seek(io, position, RW_SEEK_SET);
    }
    virtual size_t tell() override
    {
        return io->seek(io, 0, RW_SEEK_CUR);
    }
    virtual size_t getSize() override
    {
        if (size == 0) {
            size_t cur = tell();
            size = io->seek(io, 0, RW_SEEK_END);
            seek(cur);
        }
        return size;
    }
};

DirectoryResourceProvider::DirectoryResourceProvider(string basepath)
{
    this->basepath = basepath.rstrip("\\/");
}

P<ResourceStream> DirectoryResourceProvider::getResourceStream(string filename)
{
    P<FileResourceStream> stream = new FileResourceStream(basepath + "/" + filename);
    if (stream->isOpen())
        return stream;
    return nullptr;
}

std::vector<string> DirectoryResourceProvider::findResources(string searchPattern)
{
    std::vector<string> found_files;
#if defined(ANDROID)
    //Limitation :
    //As far as I know, Android NDK won't provide a way to list subdirectories
    //So we will only list files in the first level directory
    static jobject asset_manager_jobject;
    static AAssetManager* asset_manager = nullptr;
    if (!asset_manager)
    {
        JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
        jobject activity = (jobject)SDL_AndroidGetActivity();
        jclass clazz(env->GetObjectClass(activity));
        jmethodID method_id = env->GetMethodID(clazz, "getAssets", "()Landroid/content/res/AssetManager;");
        asset_manager_jobject = env->CallObjectMethod(activity, method_id);
        asset_manager = AAssetManager_fromJava(env, asset_manager_jobject);

        env->DeleteLocalRef(activity);
        env->DeleteLocalRef(clazz);
    }

    if(asset_manager)
    {
        int idx = searchPattern.rfind("/");
        string forced_path = basepath;
        string prefix = "";
        if (idx > -1)
        {
            prefix = searchPattern.substr(0, idx);
            forced_path += "/" + prefix;
            prefix += "/";
        }
        AAssetDir* dir = AAssetManager_openDir(asset_manager, (forced_path).c_str());
        if (dir)
        {
            const char* filename;
            while ((filename = AAssetDir_getNextFileName(dir)) != nullptr)
            {
                if (searchMatch(prefix + filename, searchPattern))
                    found_files.push_back(prefix + filename);
            }
            AAssetDir_close(dir);
        }
    }
#else
    findResources(found_files, "", searchPattern);
#endif
    return found_files;
}

void DirectoryResourceProvider::findResources(std::vector<string>& found_files, const string path, const string searchPattern)
{
#ifdef _MSC_VER
    WIN32_FIND_DATAA data;
    string search_root(basepath + "/" + path);
    if (!search_root.endswith("/"))
    {
        search_root += "/";
    }
    HANDLE handle = FindFirstFileA((search_root + "*").c_str(), &data);
    if (handle == INVALID_HANDLE_VALUE)
        return;
    do
    {
        if (data.cFileName[0] == '.')
            continue;
        string name = path + string(data.cFileName);
        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            findResources(found_files, name + "/", searchPattern);
        }
        else
        {
            if (searchMatch(name, searchPattern))
                found_files.push_back(name);
        }
    } while (FindNextFileA(handle, &data));

    FindClose(handle);
#else
    DIR* dir = opendir((basepath + "/" + path).c_str());
    if (!dir)
        return;

    struct dirent *entry;
    while ((entry = readdir(dir)) != nullptr)
    {
        if (entry->d_name[0] == '.')
            continue;
        string name = path + string(entry->d_name);
        if (searchMatch(name, searchPattern))
            found_files.push_back(name);
        findResources(found_files, path + string(entry->d_name) + "/", searchPattern);
    }
    closedir(dir);
#endif
}

P<ResourceStream> getResourceStream(string filename)
{
    foreach(ResourceProvider, rp, resourceProviders)
    {
        P<ResourceStream> stream = rp->getResourceStream(filename);
        if (stream)
            return stream;
    }
    return NULL;
}

std::vector<string> findResources(string searchPattern)
{
    std::vector<string> foundFiles;
    foreach(ResourceProvider, rp, resourceProviders)
    {
        std::vector<string> res = rp->findResources(searchPattern);
        foundFiles.insert(foundFiles.end(), res.begin(), res.end());
    }
    return foundFiles;
}
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   CEGUIOpenGLESTexture.cpp
    created:    Sun Jan 11 2009
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUI/RendererModules/OpenGLES/Texture.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/System.h"
#include "CEGUI/ImageCodec.h"

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
OpenGLESTexture::OpenGLESTexture(OpenGLESRenderer& owner, const String& name) :
    d_size(0, 0),
    d_grabBuffer(0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0),
    d_owner(owner),
    d_name(name)
{
    initPixelFormatFields(PF_RGBA);
    generateOpenGLESTexture();
}

//----------------------------------------------------------------------------//
OpenGLESTexture::OpenGLESTexture(OpenGLESRenderer& owner, const String& name,
                                 const String& filename,
                                 const String& resourceGroup) :
    d_size(0, 0),
    d_grabBuffer(0),
    d_dataSize(0, 0),
    d_owner(owner),
    d_name(name)
{
    initPixelFormatFields(PF_RGBA);
    generateOpenGLESTexture();
    loadFromFile(filename, resourceGroup);
}

//----------------------------------------------------------------------------//
OpenGLESTexture::OpenGLESTexture(OpenGLESRenderer& owner, const String& name,
                                 const Sizef& size) :
    d_size(0, 0),
    d_grabBuffer(0),
    d_dataSize(0, 0),
    d_owner(owner),
    d_name(name)
{
    initPixelFormatFields(PF_RGBA);
    generateOpenGLESTexture();
    setTextureSize(size);
}

//----------------------------------------------------------------------------//
OpenGLESTexture::OpenGLESTexture(OpenGLESRenderer& owner, const String& name,
                                 GLuint tex, const Sizef& size) :
    d_ogltexture(tex),
    d_size(size),
    d_grabBuffer(0),
    d_dataSize(size),
    d_owner(owner),
    d_name(name)
{
    initPixelFormatFields(PF_RGBA);
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
OpenGLESTexture::~OpenGLESTexture()
{
    cleanupOpenGLESTexture();
}

//----------------------------------------------------------------------------//
const String& OpenGLESTexture::getName() const
{
    return d_name;
}

//----------------------------------------------------------------------------//
const Sizef& OpenGLESTexture::getSize() const
{
    return d_size;
}

//----------------------------------------------------------------------------//
const Sizef& OpenGLESTexture::getOriginalDataSize() const
{
    return d_dataSize;
}

//----------------------------------------------------------------------------//
const Vector2f& OpenGLESTexture::getTexelScaling() const
{
    return d_texelScaling;
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::loadFromFile(const String& filename,
    const String& resourceGroup)
{
    // Note from PDT:
    // There is somewhat tight coupling here between OpenGLESTexture and the
    // ImageCodec classes - we have intimate knowledge of how they are
    // implemented and that knowledge is relied upon in an unhealthy way; this
    // should be addressed at some stage.

    // load file to memory via resource provider
    RawDataContainer texFile;
    System::getSingleton().getResourceProvider()->
        loadRawDataContainer(filename, texFile, resourceGroup);

    // get and check existence of CEGUI::System (needed to access ImageCodec)
    System* sys = System::getSingletonPtr();
    if (!sys)
        CEGUI_THROW(RendererException("OpenGLESTexture::loadFromFile - "
                                      "CEGUI::System object has not been created: "
                                      "unable to access ImageCodec."));

    Texture* res = sys->getImageCodec().load(texFile, this);

    // unload file data buffer
    System::getSingleton().getResourceProvider()->
        unloadRawDataContainer(texFile);

    if (!res)
        // It's an error
        CEGUI_THROW(RendererException("OpenGLESTexture::loadFromFile - " +
                                      sys->getImageCodec().getIdentifierString()+
                                      " failed to load image '" + filename + "'."));
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::loadFromMemory(const void* buffer,
                                     const Sizef& buffer_size,
                                     PixelFormat pixel_format)
{
    if (!isPixelFormatSupported(pixel_format))
        CEGUI_THROW(InvalidRequestException("OpenGLESTexture::loadFromMemory: "
            "Data was supplied in an unsupported pixel format."));

    initPixelFormatFields(pixel_format);
    setTextureSize_impl(buffer_size);

    // store size of original data we are loading
    d_dataSize = buffer_size;
    // update scale values
    updateCachedScaleValues();

    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    // do the real work of getting the data into the texture
    glBindTexture(GL_TEXTURE_2D, d_ogltexture);

    if (d_isCompressed)
        loadCompressedTextureBuffer(buffer_size, buffer);
    else
        loadUncompressedTextureBuffer(buffer_size, buffer);

    // restore previous texture binding.
    glBindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::loadUncompressedTextureBuffer(const Sizef& buffer_size,
                                                    const void* buffer) const
{
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
                    static_cast<GLsizei>(buffer_size.d_width),
                    static_cast<GLsizei>(buffer_size.d_height),
                    d_format, d_subpixelFormat, buffer);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::loadCompressedTextureBuffer(const Sizef& buffer_size,
                                                  const void* buffer) const
{
    // Calculate buffer size in bytes
    GLsizei image_space =
        static_cast<GLsizei>(buffer_size.d_width * buffer_size.d_height);

    GLsizei num_bits =
        (d_format == GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ? 4 : 2);

    GLsizei image_size = (image_space * num_bits + 7) / 8;

    glCompressedTexImage2D(GL_TEXTURE_2D, 0, d_format,
                           static_cast<GLsizei>(buffer_size.d_width),
                           static_cast<GLsizei>(buffer_size.d_height),
                           0, image_size, buffer);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::blitFromMemory(void* sourceData, const Rectf& area)
{
    // store size of original data we are loading
    d_dataSize = area.getSize();
    setTextureSize(d_dataSize);
    // update scale values
    updateCachedScaleValues();

    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    // do the real work of getting the data into the texture
    glBindTexture(GL_TEXTURE_2D, d_ogltexture);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
                    static_cast<GLsizei>(d_dataSize.d_width),
                    static_cast<GLsizei>(d_dataSize.d_height),
                    GL_RGBA, GL_UNSIGNED_BYTE, sourceData);

    // restore previous texture binding.
    glBindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::blitToMemory(void* targetData)
{
    // TODO:
    CEGUI_THROW(RendererException(
        "OpenGLESTexture::blitToMemory: unimplemented!"));
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::setTextureSize(const Sizef& sz)
{
    initPixelFormatFields(PF_RGBA);

    setTextureSize_impl(sz);

    d_dataSize = d_size;
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::setTextureSize_impl(const Sizef& sz)
{
    const Sizef size(d_owner.getAdjustedTextureSize(sz));

    if (!d_isCompressed)
    {
        // make sure size is within boundaries
        GLfloat maxSize = static_cast<GLfloat>(d_owner.getMaxTextureSize());
        if ((size.d_width > maxSize) || (size.d_height > maxSize))
            CEGUI_THROW(RendererException(
                        "OpenGLESTexture::setTextureSize_impl: size too big"));

        // save old texture binding
        GLuint old_tex;
        glGetIntegerv(GL_TEXTURE_BINDING_2D,
                      reinterpret_cast<GLint*>(&old_tex));

        // set texture to required size
        glBindTexture(GL_TEXTURE_2D, d_ogltexture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                     static_cast<GLsizei>(size.d_width),
                     static_cast<GLsizei>(size.d_height),
                     0, d_format , d_subpixelFormat, 0);

        // restore previous texture binding.
        glBindTexture(GL_TEXTURE_2D, old_tex);
    }

    d_size = size;
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::grabTexture()
{
    CEGUI_THROW(RendererException(
        "OpenGLESTexture::grabTexture: unimplemented!"));
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::restoreTexture()
{
    CEGUI_THROW(RendererException(
        "OpenGLESTexture::restoreTexture: unimplemented!"));
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::updateCachedScaleValues()
{
    //
    // calculate what to use for x scale
    //
    const float orgW = d_dataSize.d_width;
    const float texW = d_size.d_width;

    // if texture and original data width are the same, scale is based
    // on the original size.
    // if texture is wider (and source data was not stretched), scale
    // is based on the size of the resulting texture.
    d_texelScaling.d_x = 1.0f / ((orgW == texW) ? orgW : texW);

    //
    // calculate what to use for y scale
    //
    const float orgH = d_dataSize.d_height;
    const float texH = d_size.d_height;

    // if texture and original data height are the same, scale is based
    // on the original size.
    // if texture is taller (and source data was not stretched), scale
    // is based on the size of the resulting texture.
    d_texelScaling.d_y = 1.0f / ((orgH == texH) ? orgH : texH);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::generateOpenGLESTexture()
{
    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    glGenTextures(1, &d_ogltexture);

    // set some parameters for this texture.
    glBindTexture(GL_TEXTURE_2D, d_ogltexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    // restore previous texture binding.
    glBindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::cleanupOpenGLESTexture()
{
    glDeleteTextures(1, &d_ogltexture);
    d_ogltexture = 0;
}

//----------------------------------------------------------------------------//
GLuint OpenGLESTexture::getOpenGLESTexture() const
{
    return d_ogltexture;
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::setOpenGLESTexture(GLuint tex, const Sizef& size)
{
    if (d_ogltexture != tex)
    {
        // cleanup the current state first.
        cleanupOpenGLESTexture();

        d_ogltexture = tex;
    }

    d_dataSize = d_size = size;
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
bool OpenGLESTexture::isPixelFormatSupported(const PixelFormat fmt) const
{
    switch (fmt)
    {
    case PF_RGBA:
    case PF_RGB:
    case PF_RGBA_4444:
    case PF_RGB_565:
        return true;

    case PF_PVRTC4:
    case PF_PVRTC2:
        return d_owner.isGLExtensionSupported("GL_IMG_texture_compression_pvrtc");

    default:
        return false;
    }
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::initPixelFormatFields(const PixelFormat fmt)
{
    d_isCompressed = false;

    switch (fmt)
    {
    case PF_RGBA:
        d_format = GL_RGBA;
        d_subpixelFormat = GL_UNSIGNED_BYTE;
        break;

    case PF_RGB:
        d_format = GL_RGB;
        d_subpixelFormat = GL_UNSIGNED_BYTE;
        break;

    case PF_RGB_565:
        d_format = GL_RGB;
        d_subpixelFormat = GL_UNSIGNED_SHORT_5_6_5;
        break;

    case PF_RGBA_4444:
        d_format = GL_RGBA;
        d_subpixelFormat = GL_UNSIGNED_SHORT_4_4_4_4;
        break;

    case PF_PVRTC4:
        d_format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
        d_subpixelFormat = GL_UNSIGNED_BYTE; // not really, but set for completeness.
        d_isCompressed = true;
        break;

    case PF_PVRTC2:
        d_format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
        d_subpixelFormat = GL_UNSIGNED_BYTE; // not really, but set for completeness.
        d_isCompressed = true;
        break;
    }
}

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

} // End of  CEGUI namespace section
<commit_msg>FIX: Port pixel unpack fix from GL renderer to GL ES renderer.<commit_after>/***********************************************************************
    filename:   CEGUIOpenGLESTexture.cpp
    created:    Sun Jan 11 2009
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUI/RendererModules/OpenGLES/Texture.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/System.h"
#include "CEGUI/ImageCodec.h"

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
OpenGLESTexture::OpenGLESTexture(OpenGLESRenderer& owner, const String& name) :
    d_size(0, 0),
    d_grabBuffer(0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0),
    d_owner(owner),
    d_name(name)
{
    initPixelFormatFields(PF_RGBA);
    generateOpenGLESTexture();
}

//----------------------------------------------------------------------------//
OpenGLESTexture::OpenGLESTexture(OpenGLESRenderer& owner, const String& name,
                                 const String& filename,
                                 const String& resourceGroup) :
    d_size(0, 0),
    d_grabBuffer(0),
    d_dataSize(0, 0),
    d_owner(owner),
    d_name(name)
{
    initPixelFormatFields(PF_RGBA);
    generateOpenGLESTexture();
    loadFromFile(filename, resourceGroup);
}

//----------------------------------------------------------------------------//
OpenGLESTexture::OpenGLESTexture(OpenGLESRenderer& owner, const String& name,
                                 const Sizef& size) :
    d_size(0, 0),
    d_grabBuffer(0),
    d_dataSize(0, 0),
    d_owner(owner),
    d_name(name)
{
    initPixelFormatFields(PF_RGBA);
    generateOpenGLESTexture();
    setTextureSize(size);
}

//----------------------------------------------------------------------------//
OpenGLESTexture::OpenGLESTexture(OpenGLESRenderer& owner, const String& name,
                                 GLuint tex, const Sizef& size) :
    d_ogltexture(tex),
    d_size(size),
    d_grabBuffer(0),
    d_dataSize(size),
    d_owner(owner),
    d_name(name)
{
    initPixelFormatFields(PF_RGBA);
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
OpenGLESTexture::~OpenGLESTexture()
{
    cleanupOpenGLESTexture();
}

//----------------------------------------------------------------------------//
const String& OpenGLESTexture::getName() const
{
    return d_name;
}

//----------------------------------------------------------------------------//
const Sizef& OpenGLESTexture::getSize() const
{
    return d_size;
}

//----------------------------------------------------------------------------//
const Sizef& OpenGLESTexture::getOriginalDataSize() const
{
    return d_dataSize;
}

//----------------------------------------------------------------------------//
const Vector2f& OpenGLESTexture::getTexelScaling() const
{
    return d_texelScaling;
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::loadFromFile(const String& filename,
    const String& resourceGroup)
{
    // Note from PDT:
    // There is somewhat tight coupling here between OpenGLESTexture and the
    // ImageCodec classes - we have intimate knowledge of how they are
    // implemented and that knowledge is relied upon in an unhealthy way; this
    // should be addressed at some stage.

    // load file to memory via resource provider
    RawDataContainer texFile;
    System::getSingleton().getResourceProvider()->
        loadRawDataContainer(filename, texFile, resourceGroup);

    // get and check existence of CEGUI::System (needed to access ImageCodec)
    System* sys = System::getSingletonPtr();
    if (!sys)
        CEGUI_THROW(RendererException("OpenGLESTexture::loadFromFile - "
                                      "CEGUI::System object has not been created: "
                                      "unable to access ImageCodec."));

    Texture* res = sys->getImageCodec().load(texFile, this);

    // unload file data buffer
    System::getSingleton().getResourceProvider()->
        unloadRawDataContainer(texFile);

    if (!res)
        // It's an error
        CEGUI_THROW(RendererException("OpenGLESTexture::loadFromFile - " +
                                      sys->getImageCodec().getIdentifierString()+
                                      " failed to load image '" + filename + "'."));
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::loadFromMemory(const void* buffer,
                                     const Sizef& buffer_size,
                                     PixelFormat pixel_format)
{
    if (!isPixelFormatSupported(pixel_format))
        CEGUI_THROW(InvalidRequestException("OpenGLESTexture::loadFromMemory: "
            "Data was supplied in an unsupported pixel format."));

    initPixelFormatFields(pixel_format);
    setTextureSize_impl(buffer_size);

    // store size of original data we are loading
    d_dataSize = buffer_size;
    // update scale values
    updateCachedScaleValues();

    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    // do the real work of getting the data into the texture
    glBindTexture(GL_TEXTURE_2D, d_ogltexture);

    if (d_isCompressed)
        loadCompressedTextureBuffer(buffer_size, buffer);
    else
        loadUncompressedTextureBuffer(buffer_size, buffer);

    // restore previous texture binding.
    glBindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::loadUncompressedTextureBuffer(const Sizef& buffer_size,
                                                    const void* buffer) const
{
    GLint old_pack;
    glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_pack);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
                    static_cast<GLsizei>(buffer_size.d_width),
                    static_cast<GLsizei>(buffer_size.d_height),
                    d_format, d_subpixelFormat, buffer);

    glPixelStorei(GL_UNPACK_ALIGNMENT, old_pack);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::loadCompressedTextureBuffer(const Sizef& buffer_size,
                                                  const void* buffer) const
{
    // Calculate buffer size in bytes
    GLsizei image_space =
        static_cast<GLsizei>(buffer_size.d_width * buffer_size.d_height);

    GLsizei num_bits =
        (d_format == GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ? 4 : 2);

    GLsizei image_size = (image_space * num_bits + 7) / 8;

    glCompressedTexImage2D(GL_TEXTURE_2D, 0, d_format,
                           static_cast<GLsizei>(buffer_size.d_width),
                           static_cast<GLsizei>(buffer_size.d_height),
                           0, image_size, buffer);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::blitFromMemory(void* sourceData, const Rectf& area)
{
    // store size of original data we are loading
    d_dataSize = area.getSize();
    setTextureSize(d_dataSize);
    // update scale values
    updateCachedScaleValues();

    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    // do the real work of getting the data into the texture
    glBindTexture(GL_TEXTURE_2D, d_ogltexture);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
                    static_cast<GLsizei>(d_dataSize.d_width),
                    static_cast<GLsizei>(d_dataSize.d_height),
                    GL_RGBA, GL_UNSIGNED_BYTE, sourceData);

    // restore previous texture binding.
    glBindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::blitToMemory(void* targetData)
{
    // TODO:
    CEGUI_THROW(RendererException(
        "OpenGLESTexture::blitToMemory: unimplemented!"));
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::setTextureSize(const Sizef& sz)
{
    initPixelFormatFields(PF_RGBA);

    setTextureSize_impl(sz);

    d_dataSize = d_size;
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::setTextureSize_impl(const Sizef& sz)
{
    const Sizef size(d_owner.getAdjustedTextureSize(sz));

    if (!d_isCompressed)
    {
        // make sure size is within boundaries
        GLfloat maxSize = static_cast<GLfloat>(d_owner.getMaxTextureSize());
        if ((size.d_width > maxSize) || (size.d_height > maxSize))
            CEGUI_THROW(RendererException(
                        "OpenGLESTexture::setTextureSize_impl: size too big"));

        // save old texture binding
        GLuint old_tex;
        glGetIntegerv(GL_TEXTURE_BINDING_2D,
                      reinterpret_cast<GLint*>(&old_tex));

        // set texture to required size
        glBindTexture(GL_TEXTURE_2D, d_ogltexture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                     static_cast<GLsizei>(size.d_width),
                     static_cast<GLsizei>(size.d_height),
                     0, d_format , d_subpixelFormat, 0);

        // restore previous texture binding.
        glBindTexture(GL_TEXTURE_2D, old_tex);
    }

    d_size = size;
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::grabTexture()
{
    CEGUI_THROW(RendererException(
        "OpenGLESTexture::grabTexture: unimplemented!"));
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::restoreTexture()
{
    CEGUI_THROW(RendererException(
        "OpenGLESTexture::restoreTexture: unimplemented!"));
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::updateCachedScaleValues()
{
    //
    // calculate what to use for x scale
    //
    const float orgW = d_dataSize.d_width;
    const float texW = d_size.d_width;

    // if texture and original data width are the same, scale is based
    // on the original size.
    // if texture is wider (and source data was not stretched), scale
    // is based on the size of the resulting texture.
    d_texelScaling.d_x = 1.0f / ((orgW == texW) ? orgW : texW);

    //
    // calculate what to use for y scale
    //
    const float orgH = d_dataSize.d_height;
    const float texH = d_size.d_height;

    // if texture and original data height are the same, scale is based
    // on the original size.
    // if texture is taller (and source data was not stretched), scale
    // is based on the size of the resulting texture.
    d_texelScaling.d_y = 1.0f / ((orgH == texH) ? orgH : texH);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::generateOpenGLESTexture()
{
    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    glGenTextures(1, &d_ogltexture);

    // set some parameters for this texture.
    glBindTexture(GL_TEXTURE_2D, d_ogltexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    // restore previous texture binding.
    glBindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::cleanupOpenGLESTexture()
{
    glDeleteTextures(1, &d_ogltexture);
    d_ogltexture = 0;
}

//----------------------------------------------------------------------------//
GLuint OpenGLESTexture::getOpenGLESTexture() const
{
    return d_ogltexture;
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::setOpenGLESTexture(GLuint tex, const Sizef& size)
{
    if (d_ogltexture != tex)
    {
        // cleanup the current state first.
        cleanupOpenGLESTexture();

        d_ogltexture = tex;
    }

    d_dataSize = d_size = size;
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
bool OpenGLESTexture::isPixelFormatSupported(const PixelFormat fmt) const
{
    switch (fmt)
    {
    case PF_RGBA:
    case PF_RGB:
    case PF_RGBA_4444:
    case PF_RGB_565:
        return true;

    case PF_PVRTC4:
    case PF_PVRTC2:
        return d_owner.isGLExtensionSupported("GL_IMG_texture_compression_pvrtc");

    default:
        return false;
    }
}

//----------------------------------------------------------------------------//
void OpenGLESTexture::initPixelFormatFields(const PixelFormat fmt)
{
    d_isCompressed = false;

    switch (fmt)
    {
    case PF_RGBA:
        d_format = GL_RGBA;
        d_subpixelFormat = GL_UNSIGNED_BYTE;
        break;

    case PF_RGB:
        d_format = GL_RGB;
        d_subpixelFormat = GL_UNSIGNED_BYTE;
        break;

    case PF_RGB_565:
        d_format = GL_RGB;
        d_subpixelFormat = GL_UNSIGNED_SHORT_5_6_5;
        break;

    case PF_RGBA_4444:
        d_format = GL_RGBA;
        d_subpixelFormat = GL_UNSIGNED_SHORT_4_4_4_4;
        break;

    case PF_PVRTC4:
        d_format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
        d_subpixelFormat = GL_UNSIGNED_BYTE; // not really, but set for completeness.
        d_isCompressed = true;
        break;

    case PF_PVRTC2:
        d_format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
        d_subpixelFormat = GL_UNSIGNED_BYTE; // not really, but set for completeness.
        d_isCompressed = true;
        break;
    }
}

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

} // End of  CEGUI namespace section
<|endoftext|>