<commit_before>/*
 * player.cpp
 *
 *  Created on: May 4, 2013
 *      Author: nikita.karnauhov@gmail.com
 */

#include "player.h"

#include <list>
#include <set>
#include <thread>
#include <mutex>

#include <alsa/asoundlib.h>

#include "alsa_wrapper.h"
#include "formats.h"

struct Samples {
    uint64_t cTimestamp;
    std::string data;
    size_t cOffset;

    Samples(unap::Packet &_packet) :
        cTimestamp(_packet.timestamp()), data(std::move(*_packet.mutable_samples())), cOffset(0)
    {
    }

    bool operator <(const Samples &_other) const {
        return cTimestamp < _other.cTimestamp;
    }

    const char *getData(size_t _cFrameBytes) const {
        return data.c_str() + cOffset*_cFrameBytes;
    }

    size_t getFrameCount(size_t _cFrameBytes) const {
        return data.size()/_cFrameBytes - cOffset;
    }
};

template<class _T>
struct PtrLess {
    bool operator ()(const _T *_pLhs, const _T *_pRhs) const {
        return *_pLhs < *_pRhs;
    }
};

typedef std::set<Samples *, PtrLess<Samples> > SampleQueue;

class Player::Impl {
public:
    Impl(uint64_t _cStreamId, Log &_log) :
        m_cStreamId(_cStreamId), m_pPcm(nullptr), m_cBufferSize(4096), m_cPeriodSize(256),
        m_format(SND_PCM_FORMAT_UNKNOWN), m_cRate(0), m_cChannelCount(0), m_cFrameBytes(0),
        m_cPosition(0), m_pLog(&_log), m_bReady(false) {}

    ~Impl() {
        ALSA::drain(m_pPcm);
        m_pPcm = nullptr;
    }

    static Player *get(unap::Packet &_packet, Log &_log);

    bool is_prepared() const {
        return m_pPcm != nullptr;
    }

    void init(unap::Packet &_packet);
    void run();
    void play(unap::Packet &_packet);

private:
    uint64_t m_cStreamId;
    snd_pcm_t *m_pPcm;
    snd_pcm_uframes_t m_cBufferSize;
    snd_pcm_uframes_t m_cPeriodSize;
    SampleQueue m_queue;
    snd_pcm_format_t m_format;
    unsigned int m_cRate;
    size_t m_cChannelCount;
    size_t m_cFrameBytes;
    size_t m_cPosition;
    std::thread m_worker;
    mutable std::mutex m_mutex;
    Log *m_pLog;
    bool m_bReady;

    typedef std::map<uint64_t, Player *> Players;
    static Players s_players;
    static std::mutex s_playerMapMutex;

    void _add_samples(size_t _cSamples, bool _bStopWhenEmpty);
};

Player *Player::Impl::get(unap::Packet &_packet, Log &_log) {
    std::lock_guard<std::mutex> lock(s_playerMapMutex);
    auto player = s_players.insert(std::make_pair(_packet.stream(), nullptr));

    if (player.second)
        player.first->second = new Player(_packet.stream(), _log);

    return player.first->second;
}

void Player::Impl::init(unap::Packet &_packet) {
    try {
        snd_pcm_hw_params_t *pParams;

        ALSA::open(&m_pPcm, "default", SND_PCM_STREAM_PLAYBACK, 0);
        ALSA::hw_params_malloc(&pParams);
        ALSA::hw_params_any(m_pPcm, pParams);
        ALSA::hw_params_set_access(m_pPcm, pParams, SND_PCM_ACCESS_RW_INTERLEAVED);
        ALSA::hw_params_set_format(m_pPcm, pParams, get_format(_packet.format()));

        unsigned int cRate = _packet.rate();

        ALSA::hw_params_set_rate_near(m_pPcm, pParams, &cRate, 0);
        ALSA::hw_params_set_channels(m_pPcm, pParams, _packet.channels());
        ALSA::hw_params_set_buffer_size_near(m_pPcm, pParams, &m_cBufferSize);
        ALSA::hw_params_set_period_size_near(m_pPcm, pParams, &m_cPeriodSize, NULL);
        ALSA::hw_params(m_pPcm, pParams);
        ALSA::hw_params_free(pParams);
        ALSA::prepare(m_pPcm);

        m_cFrameBytes = ALSA::format_physical_width(get_format(_packet.format()))*_packet.channels()/8;
        m_cPosition = 0;
        m_bReady = true;
    } catch (std::exception &e) {
        m_pLog->log(llError, e.what());
        m_bReady = false;
    }
}

void Player::Impl::play(unap::Packet &_packet) {
    std::lock_guard<std::mutex> lock(m_mutex);

    m_pLog->log(llDebug, "version = %u; stream = %llu; kind = %d, format = %s, channels = %u; rate = %u; timestamp = %llu; frames = %u",
            _packet.version(), _packet.stream(), _packet.kind(), _packet.format().c_str(),
            _packet.channels(), _packet.rate(), _packet.timestamp(), _packet.samples().size());

    if (m_cPosition <= _packet.timestamp()) {
        m_queue.insert(new Samples(_packet));

        if (m_cPosition == 0)
            m_cPosition = _packet.timestamp();
    }

    while (m_cPosition < 2*m_cPeriodSize) {
        if (m_queue.empty())
            return;

        _add_samples(2*m_cPeriodSize - m_cPosition, true);
    }

    // Dump data.
//        static int nCount = 0;
//        std::stringstream ss;
//        ss << "dump_" << std::setw(10) << std::setfill('0') << ++nCount << ".pcm";
//        std::ofstream ofs(ss.str());
//        ofs.write(_packet.samples().c_str(), _packet.samples().size());
//        size_t cFrames = _packet.samples().size()/4;
//
//        std::cerr << cFrames << std::endl;
//
//        if ((err = snd_pcm_writei(playback_handle, _packet.samples().c_str(), cFrames)) != cFrames) {
//            fprintf (stderr, "write to audio interface failed (%s)\n",
//                 snd_strerror (err));
//        }
}

void Player::Impl::run() {
    m_worker = std::thread([&]() {
        try {
            int nLastError = 0;
            constexpr size_t c_cMaxRetries = 1000;
            size_t cRetry = 0;

            while (true) {
                if (nLastError < 0) {
                    bool bEmpty = false;

                    ++cRetry;

                    {
                        std::lock_guard<std::mutex> lock(m_mutex);
                        bEmpty = m_queue.empty();
                    }

                    // Sleep until recovered.
                    if (bEmpty) {
                        if (cRetry > c_cMaxRetries) {
                            m_pLog->info("Dropping stream %llu", m_cStreamId);
                            break;
                        }

                        // TODO any way to auto-release mutex before going to sleep? condwait?
                        m_pLog->log(cRetry == 1 ? llInfo : llDebug, "Sleeping until recovered...");
                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
                        continue;
                    }

                    // Try to recover if error occurred.
                    m_pLog->info("Recovering...");

                    ALSA::recover(m_pPcm, nLastError, true);
                    nLastError = 0;

                    // TODO timeout to drop the stream.
                    continue;
                }

                try {
                    ALSA::wait(m_pPcm, 1000);

                    // Initial portion should be filled by play().
                    if (m_cPosition == 0)
                        continue;

                    std::lock_guard<std::mutex> lock(m_mutex);

                    snd_pcm_sframes_t nFrames = ALSA::avail_update(m_pPcm);

                    if (nFrames > 0 && !m_queue.empty()) {
                        nFrames = nFrames > (snd_pcm_sframes_t)m_cPeriodSize ? m_cPeriodSize : nFrames;
                        _add_samples(nFrames, true);
                    }
                } catch (ALSA::Error &e) {
                    m_pLog->log(llWarning, e.what());
                    nLastError = e.getError();
                    continue;
                }
            }
        } catch (std::exception &e) {
            m_pLog->log(llError, e.what());
        }
    });
}

void Player::Impl::_add_samples(size_t _cSamples, bool _bStopWhenEmpty) {
    const size_t cEnd = m_cPosition + _cSamples;

    assert(m_cFrameBytes > 0);

    while (m_cPosition < cEnd) {
        Samples *pSamples = m_queue.empty() ? nullptr : *m_queue.begin();
        size_t cNext = cEnd;

        if (pSamples) {
            cNext = pSamples->cTimestamp + pSamples->cOffset;
            m_queue.erase(m_queue.begin());
        }

        if (m_cPosition < cNext)
            m_pLog->log(llInfo, "Inserting silence: %d, %d", m_cPosition, cNext - m_cPosition);

        // Insert silence instead of missing samples.
        while (m_cPosition < cNext) {
            static char buf[16] = {0};

            if (ALSA::writei(m_pPcm, buf, 1) != 1)
                break;

            ++m_cPosition;

            if (m_cPosition >= cEnd)
                break;
        }

        if (!pSamples)
            break;

        // Fill up buffer.
        const size_t cFramesQueued = pSamples->data.size()/m_cFrameBytes - pSamples->cOffset;
        const size_t cFramesRequested = cEnd - m_cPosition;

        if (const size_t cWriteSize = std::min(cFramesRequested, cFramesQueued)) {
            m_pLog->log(llDebug, "Inserting audio: %d, %d (%d)",
                    pSamples->cTimestamp + pSamples->cOffset, cWriteSize, m_cPosition);

            const size_t cBytesWritten = ALSA::writei(m_pPcm,
                    pSamples->getData(m_cFrameBytes), cWriteSize);

            pSamples->cOffset += cBytesWritten;
            m_cPosition += cBytesWritten;
        }

        if (pSamples->cOffset*m_cFrameBytes < pSamples->data.size())
            m_queue.insert(pSamples);
        else
            delete pSamples;

        if (m_queue.empty() && _bStopWhenEmpty)
            break;
    }
}

Player::Impl::Players Player::Impl::s_players{};
std::mutex Player::Impl::s_playerMapMutex{};

Player::Player(uint64_t _cStreamId, Log &_log) : m_pImpl(new Impl(_cStreamId, _log)) {
}

Player::~Player() {
    delete m_pImpl;
}

Player *Player::get(unap::Packet &_packet, Log &_log) {
    return Impl::get(_packet, _log);
}

bool Player::is_prepared() const {
    return m_pImpl->is_prepared();
}

void Player::init(unap::Packet &_packet) {
    m_pImpl->init(_packet);
}

void Player::run() {
    m_pImpl->run();
}

void Player::play(unap::Packet &_packet) {
    m_pImpl->play(_packet);
}
<commit_msg>Close PCM after timeout.<commit_after>/*
 * player.cpp
 *
 *  Created on: May 4, 2013
 *      Author: nikita.karnauhov@gmail.com
 */

#include "player.h"

#include <list>
#include <set>
#include <thread>
#include <mutex>

#include <alsa/asoundlib.h>

#include "alsa_wrapper.h"
#include "formats.h"

struct Samples {
    uint64_t cTimestamp;
    std::string data;
    size_t cOffset;

    Samples(unap::Packet &_packet) :
        cTimestamp(_packet.timestamp()), data(std::move(*_packet.mutable_samples())), cOffset(0)
    {
    }

    bool operator <(const Samples &_other) const {
        return cTimestamp < _other.cTimestamp;
    }

    const char *getData(size_t _cFrameBytes) const {
        return data.c_str() + cOffset*_cFrameBytes;
    }

    size_t getFrameCount(size_t _cFrameBytes) const {
        return data.size()/_cFrameBytes - cOffset;
    }
};

template<class _T>
struct PtrLess {
    bool operator ()(const _T *_pLhs, const _T *_pRhs) const {
        return *_pLhs < *_pRhs;
    }
};

typedef std::set<Samples *, PtrLess<Samples> > SampleQueue;

class Player::Impl {
public:
    Impl(uint64_t _cStreamId, Log &_log) :
        m_cStreamId(_cStreamId), m_pPcm(nullptr), m_cBufferSize(4096), m_cPeriodSize(256),
        m_format(SND_PCM_FORMAT_UNKNOWN), m_cRate(0), m_cChannelCount(0), m_cFrameBytes(0),
        m_cPosition(0), m_pLog(&_log), m_bReady(false) {}

    ~Impl() {
        ALSA::drain(m_pPcm);
        m_pPcm = nullptr;
    }

    static Player *get(unap::Packet &_packet, Log &_log);

    bool is_prepared() const {
        return m_pPcm != nullptr;
    }

    void init(unap::Packet &_packet);
    void run();
    void play(unap::Packet &_packet);

private:
    uint64_t m_cStreamId;
    snd_pcm_t *m_pPcm;
    snd_pcm_uframes_t m_cBufferSize;
    snd_pcm_uframes_t m_cPeriodSize;
    SampleQueue m_queue;
    snd_pcm_format_t m_format;
    unsigned int m_cRate;
    size_t m_cChannelCount;
    size_t m_cFrameBytes;
    size_t m_cPosition;
    std::thread m_worker;
    mutable std::mutex m_mutex;
    Log *m_pLog;
    bool m_bReady;

    typedef std::map<uint64_t, Player *> Players;
    static Players s_players;
    static std::mutex s_playerMapMutex;

    void _add_samples(size_t _cSamples, bool _bStopWhenEmpty);
};

Player *Player::Impl::get(unap::Packet &_packet, Log &_log) {
    std::lock_guard<std::mutex> lock(s_playerMapMutex);
    auto player = s_players.insert(std::make_pair(_packet.stream(), nullptr));

    if (player.second)
        player.first->second = new Player(_packet.stream(), _log);

    return player.first->second;
}

void Player::Impl::init(unap::Packet &_packet) {
    try {
        snd_pcm_hw_params_t *pParams;

        ALSA::open(&m_pPcm, "default", SND_PCM_STREAM_PLAYBACK, 0);
        ALSA::hw_params_malloc(&pParams);
        ALSA::hw_params_any(m_pPcm, pParams);
        ALSA::hw_params_set_access(m_pPcm, pParams, SND_PCM_ACCESS_RW_INTERLEAVED);
        ALSA::hw_params_set_format(m_pPcm, pParams, get_format(_packet.format()));

        unsigned int cRate = _packet.rate();

        ALSA::hw_params_set_rate_near(m_pPcm, pParams, &cRate, 0);
        ALSA::hw_params_set_channels(m_pPcm, pParams, _packet.channels());
        ALSA::hw_params_set_buffer_size_near(m_pPcm, pParams, &m_cBufferSize);
        ALSA::hw_params_set_period_size_near(m_pPcm, pParams, &m_cPeriodSize, NULL);
        ALSA::hw_params(m_pPcm, pParams);
        ALSA::hw_params_free(pParams);
        ALSA::prepare(m_pPcm);

        m_cFrameBytes = ALSA::format_physical_width(get_format(_packet.format()))*_packet.channels()/8;
        m_cPosition = 0;
        m_bReady = true;
    } catch (std::exception &e) {
        m_pLog->log(llError, e.what());
        m_bReady = false;
    }
}

void Player::Impl::play(unap::Packet &_packet) {
    std::lock_guard<std::mutex> lock(m_mutex);

    m_pLog->log(llDebug, "version = %u; stream = %llu; kind = %d, format = %s, channels = %u; rate = %u; timestamp = %llu; frames = %u",
            _packet.version(), _packet.stream(), _packet.kind(), _packet.format().c_str(),
            _packet.channels(), _packet.rate(), _packet.timestamp(), _packet.samples().size());

    if (m_cPosition <= _packet.timestamp()) {
        m_queue.insert(new Samples(_packet));

        if (m_cPosition == 0)
            m_cPosition = _packet.timestamp();
    }

    while (m_cPosition < 2*m_cPeriodSize) {
        if (m_queue.empty())
            return;

        _add_samples(2*m_cPeriodSize - m_cPosition, true);
    }

    // Dump data.
//        static int nCount = 0;
//        std::stringstream ss;
//        ss << "dump_" << std::setw(10) << std::setfill('0') << ++nCount << ".pcm";
//        std::ofstream ofs(ss.str());
//        ofs.write(_packet.samples().c_str(), _packet.samples().size());
//        size_t cFrames = _packet.samples().size()/4;
//
//        std::cerr << cFrames << std::endl;
//
//        if ((err = snd_pcm_writei(playback_handle, _packet.samples().c_str(), cFrames)) != cFrames) {
//            fprintf (stderr, "write to audio interface failed (%s)\n",
//                 snd_strerror (err));
//        }
}

void Player::Impl::run() {
    m_worker = std::thread([&]() {
        try {
            int nLastError = 0;
            constexpr size_t c_cMaxRetries = 1000;
            size_t cRetry = 0;

            while (true) {
                if (nLastError < 0) {
                    bool bEmpty = false;

                    ++cRetry;

                    {
                        std::lock_guard<std::mutex> lock(m_mutex);
                        bEmpty = m_queue.empty();
                    }

                    // Sleep until recovered.
                    if (bEmpty) {
                        if (cRetry > c_cMaxRetries) {
                            m_pLog->info("Dropping stream %llu", m_cStreamId);
                            ALSA::close(m_pPcm);
                            break;
                        }

                        // TODO any way to auto-release mutex before going to sleep? condwait?
                        m_pLog->log(cRetry == 1 ? llInfo : llDebug, "Sleeping until recovered...");
                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
                        continue;
                    }

                    // Try to recover if error occurred.
                    m_pLog->info("Recovering...");

                    ALSA::recover(m_pPcm, nLastError, true);
                    nLastError = 0;

                    // TODO timeout to drop the stream.
                    continue;
                }

                try {
                    ALSA::wait(m_pPcm, 1000);

                    // Initial portion should be filled by play().
                    if (m_cPosition == 0)
                        continue;

                    std::lock_guard<std::mutex> lock(m_mutex);

                    snd_pcm_sframes_t nFrames = ALSA::avail_update(m_pPcm);

                    if (nFrames > 0 && !m_queue.empty()) {
                        nFrames = nFrames > (snd_pcm_sframes_t)m_cPeriodSize ? m_cPeriodSize : nFrames;
                        _add_samples(nFrames, true);
                    }
                } catch (ALSA::Error &e) {
                    m_pLog->log(llWarning, e.what());
                    nLastError = e.getError();
                    continue;
                }
            }
        } catch (std::exception &e) {
            m_pLog->log(llError, e.what());
        }
    });
}

void Player::Impl::_add_samples(size_t _cSamples, bool _bStopWhenEmpty) {
    const size_t cEnd = m_cPosition + _cSamples;

    assert(m_cFrameBytes > 0);

    while (m_cPosition < cEnd) {
        Samples *pSamples = m_queue.empty() ? nullptr : *m_queue.begin();
        size_t cNext = cEnd;

        if (pSamples) {
            cNext = pSamples->cTimestamp + pSamples->cOffset;
            m_queue.erase(m_queue.begin());
        }

        if (m_cPosition < cNext)
            m_pLog->log(llInfo, "Inserting silence: %d, %d", m_cPosition, cNext - m_cPosition);

        // Insert silence instead of missing samples.
        while (m_cPosition < cNext) {
            static char buf[16] = {0};

            if (ALSA::writei(m_pPcm, buf, 1) != 1)
                break;

            ++m_cPosition;

            if (m_cPosition >= cEnd)
                break;
        }

        if (!pSamples)
            break;

        // Fill up buffer.
        const size_t cFramesQueued = pSamples->data.size()/m_cFrameBytes - pSamples->cOffset;
        const size_t cFramesRequested = cEnd - m_cPosition;

        if (const size_t cWriteSize = std::min(cFramesRequested, cFramesQueued)) {
            m_pLog->log(llDebug, "Inserting audio: %d, %d (%d)",
                    pSamples->cTimestamp + pSamples->cOffset, cWriteSize, m_cPosition);

            const size_t cBytesWritten = ALSA::writei(m_pPcm,
                    pSamples->getData(m_cFrameBytes), cWriteSize);

            pSamples->cOffset += cBytesWritten;
            m_cPosition += cBytesWritten;
        }

        if (pSamples->cOffset*m_cFrameBytes < pSamples->data.size())
            m_queue.insert(pSamples);
        else
            delete pSamples;

        if (m_queue.empty() && _bStopWhenEmpty)
            break;
    }
}

Player::Impl::Players Player::Impl::s_players{};
std::mutex Player::Impl::s_playerMapMutex{};

Player::Player(uint64_t _cStreamId, Log &_log) : m_pImpl(new Impl(_cStreamId, _log)) {
}

Player::~Player() {
    delete m_pImpl;
}

Player *Player::get(unap::Packet &_packet, Log &_log) {
    return Impl::get(_packet, _log);
}

bool Player::is_prepared() const {
    return m_pImpl->is_prepared();
}

void Player::init(unap::Packet &_packet) {
    m_pImpl->init(_packet);
}

void Player::run() {
    m_pImpl->run();
}

void Player::play(unap::Packet &_packet) {
    m_pImpl->play(_packet);
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 1999 - 2007 Simon Peter <dn.tlp@gmx.net>
  Copyright (c) 2002 Nikita V. Kalaganov <riven@ok.ru>

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

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

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

#include "plugin.h"

#ifdef DEBUG
#	include "debug.h"
#endif

HINSTANCE		myInstance;
HWND			*myWindow;

extern In_Module	mod;

Config			config;
FileTypes		filetypes;
MyPlayer		my_player;
GuiDlgAbout		dlg_about;
GuiDlgConfig		dlg_config;
GuiDlgInfo		dlg_info;

void wa2_Init()
{
  myInstance = mod.hDllInstance;
  myWindow = &mod.hMainWindow;
}

void wa2_Quit()
{
  free(mod.FileExtensions);
  config.set_ignored(filetypes.get_ignore_list());
  config.save();
}

int wa2_IsOurFile(char *fn)
{
  // ignored ?
  if (filetypes.grata(fn))
    {
      CSilentopl silent;

      // try to make adplug player
      CPlayer *p = CAdPlug::factory(fn,&silent);

      if (p)
	{
	  delete p;
	  return 1;
	}
    }

  return 0;
}

void wa2_GetFileInfo(char *file, char *title, int *length_in_ms)
{
  const char *my_file;

  // current file ?
  if ((!file) || (!(*file)))
    my_file = my_player.get_file();
  else
    {
      // our file ?
      if (!wa2_IsOurFile(file))
	return;

      my_file = file;
    }

  // set default info
  if (title)
    strcpy(title,strrchr(my_file,'\\')+1);

  if (length_in_ms)
    *length_in_ms = 0;

  // try to get real info
  CSilentopl silent;

  CPlayer *p = CAdPlug::factory(my_file,&silent);

  if (p)
    {
      if (title)
	if (!p->gettitle().empty())
	  strcpy(title,p->gettitle().c_str());

      if (length_in_ms)
	if (file)
	  *length_in_ms = my_player.get_length(my_file,my_player.get_subsong());
	else
	  *length_in_ms = my_player.get_length(my_file,DFL_SUBSONG);

      delete p;
    }
}

int wa2_Play(char *fn)
{
  return my_player.play(fn);
}

void wa2_Pause()
{
  my_player.pause();
}

void wa2_UnPause()
{
  my_player.unpause();
}

int wa2_IsPaused()
{
  return my_player.is_paused();
}

void wa2_Stop()
{
  my_player.stop();
}

int wa2_GetLength()
{
  return my_player.get_length();
}

int wa2_GetOutputTime()
{
  return my_player.get_position();
}

void wa2_SetOutputTime(int time_in_ms)
{
  my_player.seek(time_in_ms);
}

void wa2_SetVolume(int volume)
{
  my_player.set_volume(volume);
}

void wa2_SetPan(int pan)
{
  my_player.set_panning(pan);
}

void wa2_EqSet(int on, char data[10], int preamp)
{
  return;
}

void wa2_DlgAbout(HWND hwndParent)
{
  dlg_about.open(hwndParent);
}

void wa2_DlgConfig(HWND hwndParent)
{
  dlg_config.open(hwndParent);
}

int wa2_DlgInfo(char *file, HWND hwndParent)
{
  return dlg_info.open(file,hwndParent);
}

In_Module mod =
  {
    IN_VER,
    PLUGIN_VER,
    0,
    0,
    0,
    1,
    1,
    wa2_DlgConfig,
    wa2_DlgAbout,
    wa2_Init,
    wa2_Quit,
    wa2_GetFileInfo,
    wa2_DlgInfo,
    wa2_IsOurFile,
    wa2_Play,
    wa2_Pause,
    wa2_UnPause,
    wa2_IsPaused,
    wa2_Stop,
    wa2_GetLength,
    wa2_GetOutputTime,
    wa2_SetOutputTime,
    wa2_SetVolume,
    wa2_SetPan,
    0,0,0,0,0,0,0,0,0,
    0,0,
    wa2_EqSet,
    0,
    0
  };

extern "C" __declspec(dllexport) In_Module *winampGetInModule2()
{
  t_config_data	cfg;

#ifdef DEBUG
  debug_init();
#endif
  config.load();
  config.get(&cfg);

  mod.UsesOutputPlug = config.useoutputplug;

  filetypes.add("a2m", "Adlib Tracker 2 Modules (*.A2M)");
  filetypes.add("adl", "Westwood ADL Files (*.ADL)");
  filetypes.add("amd", "AMUSIC Modules (*.AMD)");
  filetypes.add("bam", "Bob's Adlib Music Files (*.BAM)");
  filetypes.add("cff", "BoomTracker 4 Modules (*.CFF)");
  filetypes.add("cmf", "Creative Adlib Music Files (*.CMF)");
  filetypes.add("d00", "Packed EdLib Modules (*.D00)");
  filetypes.add("dfm", "Digital-FM Modules (*.DFM)");
  filetypes.add("dmo", "TwinTeam Modules (*.DMO)");
  filetypes.add("dro", "DOSBox Raw OPL v1.0 and v2.0 Files (*.DRO)");
  filetypes.add("dtm", "DeFy Adlib Tracker Modules (*.DTM)");
  filetypes.add("hsc", "HSC-Tracker Modules (*.HSC)");
  filetypes.add("hsp", "Packed HSC-Tracker Modules (*.HSP)");
  filetypes.add("imf;wlf;adlib", "Apogee IMF Files (*.IMF;*.WLF;*.ADLIB)");
  filetypes.add("jbm", "JBM Adlib Music Files (*.JBM)");
  filetypes.add("ksm", "Ken Silverman's Music Files (*.KSM)");
  filetypes.add("laa", "LucasArts Adlib Audio Files (*.LAA)");
  filetypes.add("lds", "LOUDNESS Sound System Files (*.LDS)");
  filetypes.add("m", "Ultima 6 Music Files (*.M)");
  filetypes.add("mad", "Mlat Adlib Tracker Modules (*.MAD)");
  filetypes.add("mid;kar", "MIDI Audio Files (*.MID;*.KAR)");
  filetypes.add("mkj", "MKJamz Audio Files (*.MKJ)");
  filetypes.add("msc", "AdLib MSCplay (*.MSC)");
  filetypes.add("mtk", "MPU-401 Trakker Modules (*.MTK)");
  filetypes.add("rad", "Reality Adlib Tracker Modules (*.RAD)");
  filetypes.add("raw", "Rdos RAW Files (*.RAW)");
  filetypes.add("rix", "Softstar RIX OPL Music Files (*.RIX)");
  filetypes.add("rol", "Adlib Visual Composer Modules (*.ROL)");
  if(!cfg.s3m_workaround) {
    filetypes.add("s3m", "Scream Tracker 3 Modules (*.S3M)");
  }
  filetypes.add("sa2", "Surprise! Adlib Tracker 2 Modules (*.SA2)");
  filetypes.add("sat", "Surprise! Adlib Tracker Modules (*.SAT)");
  filetypes.add("sci", "Sierra Adlib Audio Files (*.SCI)");
  filetypes.add("sng", "Adlib Tracker 1.0 Modules (*.SNG)");
  filetypes.add("sng", "Faust Music Creator Modules (*.SNG)");
  filetypes.add("sng", "SNGPlay Files (*.SNG)");
  filetypes.add("xad", "eXotic Adlib Files (*.XAD)");
  filetypes.add("xms", "XMS-Tracker Modules (*.XMS)");
  filetypes.add("xsm", "eXtra Simple Music Files (*.XSM)");

  filetypes.set_ignore_list(config.get_ignored());

  mod.FileExtensions = filetypes.export_filetypes((char *)malloc(4096));

  return &mod;
}
<commit_msg>Add *.GOT extension<commit_after>/*
  Copyright (c) 1999 - 2007 Simon Peter <dn.tlp@gmx.net>
  Copyright (c) 2002 Nikita V. Kalaganov <riven@ok.ru>

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

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

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

#include "plugin.h"

#ifdef DEBUG
#	include "debug.h"
#endif

HINSTANCE		myInstance;
HWND			*myWindow;

extern In_Module	mod;

Config			config;
FileTypes		filetypes;
MyPlayer		my_player;
GuiDlgAbout		dlg_about;
GuiDlgConfig		dlg_config;
GuiDlgInfo		dlg_info;

void wa2_Init()
{
  myInstance = mod.hDllInstance;
  myWindow = &mod.hMainWindow;
}

void wa2_Quit()
{
  free(mod.FileExtensions);
  config.set_ignored(filetypes.get_ignore_list());
  config.save();
}

int wa2_IsOurFile(char *fn)
{
  // ignored ?
  if (filetypes.grata(fn))
    {
      CSilentopl silent;

      // try to make adplug player
      CPlayer *p = CAdPlug::factory(fn,&silent);

      if (p)
	{
	  delete p;
	  return 1;
	}
    }

  return 0;
}

void wa2_GetFileInfo(char *file, char *title, int *length_in_ms)
{
  const char *my_file;

  // current file ?
  if ((!file) || (!(*file)))
    my_file = my_player.get_file();
  else
    {
      // our file ?
      if (!wa2_IsOurFile(file))
	return;

      my_file = file;
    }

  // set default info
  if (title)
    strcpy(title,strrchr(my_file,'\\')+1);

  if (length_in_ms)
    *length_in_ms = 0;

  // try to get real info
  CSilentopl silent;

  CPlayer *p = CAdPlug::factory(my_file,&silent);

  if (p)
    {
      if (title)
	if (!p->gettitle().empty())
	  strcpy(title,p->gettitle().c_str());

      if (length_in_ms)
	if (file)
	  *length_in_ms = my_player.get_length(my_file,my_player.get_subsong());
	else
	  *length_in_ms = my_player.get_length(my_file,DFL_SUBSONG);

      delete p;
    }
}

int wa2_Play(char *fn)
{
  return my_player.play(fn);
}

void wa2_Pause()
{
  my_player.pause();
}

void wa2_UnPause()
{
  my_player.unpause();
}

int wa2_IsPaused()
{
  return my_player.is_paused();
}

void wa2_Stop()
{
  my_player.stop();
}

int wa2_GetLength()
{
  return my_player.get_length();
}

int wa2_GetOutputTime()
{
  return my_player.get_position();
}

void wa2_SetOutputTime(int time_in_ms)
{
  my_player.seek(time_in_ms);
}

void wa2_SetVolume(int volume)
{
  my_player.set_volume(volume);
}

void wa2_SetPan(int pan)
{
  my_player.set_panning(pan);
}

void wa2_EqSet(int on, char data[10], int preamp)
{
  return;
}

void wa2_DlgAbout(HWND hwndParent)
{
  dlg_about.open(hwndParent);
}

void wa2_DlgConfig(HWND hwndParent)
{
  dlg_config.open(hwndParent);
}

int wa2_DlgInfo(char *file, HWND hwndParent)
{
  return dlg_info.open(file,hwndParent);
}

In_Module mod =
  {
    IN_VER,
    PLUGIN_VER,
    0,
    0,
    0,
    1,
    1,
    wa2_DlgConfig,
    wa2_DlgAbout,
    wa2_Init,
    wa2_Quit,
    wa2_GetFileInfo,
    wa2_DlgInfo,
    wa2_IsOurFile,
    wa2_Play,
    wa2_Pause,
    wa2_UnPause,
    wa2_IsPaused,
    wa2_Stop,
    wa2_GetLength,
    wa2_GetOutputTime,
    wa2_SetOutputTime,
    wa2_SetVolume,
    wa2_SetPan,
    0,0,0,0,0,0,0,0,0,
    0,0,
    wa2_EqSet,
    0,
    0
  };

extern "C" __declspec(dllexport) In_Module *winampGetInModule2()
{
  t_config_data	cfg;

#ifdef DEBUG
  debug_init();
#endif
  config.load();
  config.get(&cfg);

  mod.UsesOutputPlug = config.useoutputplug;

  filetypes.add("a2m", "Adlib Tracker 2 Modules (*.A2M)");
  filetypes.add("adl", "Westwood ADL Files (*.ADL)");
  filetypes.add("amd", "AMUSIC Modules (*.AMD)");
  filetypes.add("bam", "Bob's Adlib Music Files (*.BAM)");
  filetypes.add("cff", "BoomTracker 4 Modules (*.CFF)");
  filetypes.add("cmf", "Creative Adlib Music Files (*.CMF)");
  filetypes.add("d00", "Packed EdLib Modules (*.D00)");
  filetypes.add("dfm", "Digital-FM Modules (*.DFM)");
  filetypes.add("dmo", "TwinTeam Modules (*.DMO)");
  filetypes.add("dro", "DOSBox Raw OPL v1.0 and v2.0 Files (*.DRO)");
  filetypes.add("dtm", "DeFy Adlib Tracker Modules (*.DTM)");
  filetypes.add("got", "God of Thunder Music (*.GOT)");
  filetypes.add("hsc", "HSC-Tracker Modules (*.HSC)");
  filetypes.add("hsp", "Packed HSC-Tracker Modules (*.HSP)");
  filetypes.add("imf;wlf;adlib", "Apogee IMF Files (*.IMF;*.WLF;*.ADLIB)");
  filetypes.add("jbm", "JBM Adlib Music Files (*.JBM)");
  filetypes.add("ksm", "Ken Silverman's Music Files (*.KSM)");
  filetypes.add("laa", "LucasArts Adlib Audio Files (*.LAA)");
  filetypes.add("lds", "LOUDNESS Sound System Files (*.LDS)");
  filetypes.add("m", "Ultima 6 Music Files (*.M)");
  filetypes.add("mad", "Mlat Adlib Tracker Modules (*.MAD)");
  filetypes.add("mid;kar", "MIDI Audio Files (*.MID;*.KAR)");
  filetypes.add("mkj", "MKJamz Audio Files (*.MKJ)");
  filetypes.add("msc", "AdLib MSCplay (*.MSC)");
  filetypes.add("mtk", "MPU-401 Trakker Modules (*.MTK)");
  filetypes.add("rad", "Reality Adlib Tracker Modules (*.RAD)");
  filetypes.add("raw", "Rdos RAW Files (*.RAW)");
  filetypes.add("rix", "Softstar RIX OPL Music Files (*.RIX)");
  filetypes.add("rol", "Adlib Visual Composer Modules (*.ROL)");
  if(!cfg.s3m_workaround) {
    filetypes.add("s3m", "Scream Tracker 3 Modules (*.S3M)");
  }
  filetypes.add("sa2", "Surprise! Adlib Tracker 2 Modules (*.SA2)");
  filetypes.add("sat", "Surprise! Adlib Tracker Modules (*.SAT)");
  filetypes.add("sci", "Sierra Adlib Audio Files (*.SCI)");
  filetypes.add("sng", "Adlib Tracker 1.0 Modules (*.SNG)");
  filetypes.add("sng", "Faust Music Creator Modules (*.SNG)");
  filetypes.add("sng", "SNGPlay Files (*.SNG)");
  filetypes.add("xad", "eXotic Adlib Files (*.XAD)");
  filetypes.add("xms", "XMS-Tracker Modules (*.XMS)");
  filetypes.add("xsm", "eXtra Simple Music Files (*.XSM)");

  filetypes.set_ignore_list(config.get_ignored());

  mod.FileExtensions = filetypes.export_filetypes((char *)malloc(4096));

  return &mod;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/gpu_plugin/gpu_plugin.h"
#include "webkit/glue/plugins/nphostapi.h"

namespace gpu_plugin {

// Definitions of NPAPI plugin entry points.

namespace {

NPError NPP_New(NPMIMEType plugin_type, NPP instance,
                uint16 mode, int16 argc, char* argn[],
                char* argv[], NPSavedData* saved) {
  if (!instance)
    return NPERR_INVALID_INSTANCE_ERROR;

  return NPERR_NO_ERROR;
}

NPError NPP_Destroy(NPP instance, NPSavedData** saved) {
  if (!instance)
    return NPERR_INVALID_INSTANCE_ERROR;

  return NPERR_NO_ERROR;
}

NPError NPP_SetWindow(NPP instance, NPWindow* window) {
  return NPERR_NO_ERROR;
}

int16 NPP_HandleEvent(NPP instance, void* event) {
  return 0;
}

NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
  if (!instance)
    return NPERR_INVALID_INSTANCE_ERROR;
  switch (variable) {
    case NPPVpluginNeedsXEmbed:
      *static_cast<NPBool *>(value) = 1;
      return NPERR_NO_ERROR;
    default:
      return NPERR_INVALID_PARAM;
  }
}

NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
  return NPERR_NO_ERROR;
}
}

NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* funcs) {
  funcs->newp = NPP_New;
  funcs->destroy = NPP_Destroy;
  funcs->setwindow = NPP_SetWindow;
  funcs->event = NPP_HandleEvent;
  funcs->getvalue = NPP_GetValue;
  funcs->setvalue = NPP_SetValue;
  return NPERR_NO_ERROR;
}

#if defined(OS_LINUX)
NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs,
                               NPPluginFuncs* plugin_funcs) {
#else
NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs) {
#endif
  if (!browser_funcs)
    return NPERR_INVALID_FUNCTABLE_ERROR;

#if defined(OS_LINUX)
  NP_GetEntryPoints(plugin_funcs);
#endif

  return NPERR_NO_ERROR;
}

NPError API_CALL NP_Shutdown() {
  return NPERR_NO_ERROR;
}
}  // namespace gpu_plugin
<commit_msg>Dummy whitespace change to force a build.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/gpu_plugin/gpu_plugin.h"
#include "webkit/glue/plugins/nphostapi.h"

namespace gpu_plugin {

// Definitions of NPAPI plugin entry points.

namespace {

NPError NPP_New(NPMIMEType plugin_type, NPP instance,
                uint16 mode, int16 argc, char* argn[],
                char* argv[], NPSavedData* saved) {
  if (!instance)
    return NPERR_INVALID_INSTANCE_ERROR;

  return NPERR_NO_ERROR;
}

NPError NPP_Destroy(NPP instance, NPSavedData** saved) {
  if (!instance)
    return NPERR_INVALID_INSTANCE_ERROR;

  return NPERR_NO_ERROR;
}

NPError NPP_SetWindow(NPP instance, NPWindow* window) {
  return NPERR_NO_ERROR;
}

int16 NPP_HandleEvent(NPP instance, void* event) {
  return 0;
}

NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
  if (!instance)
    return NPERR_INVALID_INSTANCE_ERROR;
  switch (variable) {
    case NPPVpluginNeedsXEmbed:
      *static_cast<NPBool *>(value) = 1;
      return NPERR_NO_ERROR;
    default:
      return NPERR_INVALID_PARAM;
  }
}

NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
  return NPERR_NO_ERROR;
}

}  // namespace

NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* funcs) {
  funcs->newp = NPP_New;
  funcs->destroy = NPP_Destroy;
  funcs->setwindow = NPP_SetWindow;
  funcs->event = NPP_HandleEvent;
  funcs->getvalue = NPP_GetValue;
  funcs->setvalue = NPP_SetValue;
  return NPERR_NO_ERROR;
}

#if defined(OS_LINUX)
NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs,
                               NPPluginFuncs* plugin_funcs) {
#else
NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs) {
#endif
  if (!browser_funcs)
    return NPERR_INVALID_FUNCTABLE_ERROR;

#if defined(OS_LINUX)
  NP_GetEntryPoints(plugin_funcs);
#endif

  return NPERR_NO_ERROR;
}

NPError API_CALL NP_Shutdown() {
  return NPERR_NO_ERROR;
}
}  // namespace gpu_plugin
<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <mqueue.h>

#if defined(__linux__)
#  define MQDES_TO_FD(mqdes) (int)(mqdes)
#elif defined(__FreeBSD__)
#  define MQDES_TO_FD(mqdes) __mq_oshandle(mqdes)
#endif

using namespace node;
using namespace v8;

static Persistent<FunctionTemplate> constructor;
static Persistent<String> emit_symbol;
static Persistent<Value> read_emit_argv[1];
static Persistent<Value> write_emit_argv[1];
static const mqd_t MQDES_INVALID = (mqd_t)-1;

class PosixMQ : public ObjectWrap {
  public:
    mqd_t mqdes;
    struct mq_attr mqattrs;
    uv_poll_t* mqpollhandle;
    char* mqname;
    Persistent<Function> Emit;
    bool canread;
    bool canwrite;

    PosixMQ() : mqpollhandle(NULL), mqdes(MQDES_INVALID), mqname(NULL),
                canread(false), canwrite(false);

    ~PosixMQ() {
      if (mqdes != MQDES_INVALID) {
        close();
        delete mqpollhandle;
        mqpollhandle = NULL;
      }
      if (mqname) {
        free(mqname);
        mqname = NULL;
      }
      Emit.Dispose();
      Emit.Clear();
    }

    int close() {
      int r;
      uv_poll_stop(mqpollhandle);
      uv_close((uv_handle_t *)mqpollhandle, on_close);
      r = mq_close(mqdes);
      mqdes = MQDES_INVALID;
      return r;
    }

    static void on_close (uv_handle_t *handle) {}

    static Handle<Value> New(const Arguments& args) {
      HandleScope scope;

      if (!args.IsConstructCall()) {
        return ThrowException(Exception::TypeError(
            String::New("Use `new` to create instances of this object.")));
      }

      PosixMQ* obj = new PosixMQ();
      obj->Wrap(args.This());

      return args.This();
    }

    static Handle<Value> Open(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());
      bool doCreate = false;
      int flags = O_RDWR | O_NONBLOCK;
      mode_t mode;
      const char* name;

      if (args.Length() != 1) {
        return ThrowException(Exception::TypeError(
            String::New("Expecting 1 argument")));
      }
      if (!args[0]->IsObject()) {
        return ThrowException(Exception::TypeError(
            String::New("Argument must be an object")));
      }

      Local<Object> config = args[0]->ToObject();
      Local<Value> val;

      if (!(val = config->Get(String::New("create")))->IsUndefined()) {
        if (!val->IsBoolean()) {
          return ThrowException(Exception::TypeError(
              String::New("'create' property must be a boolean")));
        }
        doCreate = val->BooleanValue();
      }

      val = config->Get(String::New("name"));
      if (!val->IsString()) {
        return ThrowException(Exception::TypeError(
            String::New("'name' property must be a string")));
      }
      String::AsciiValue namestr(val->ToString());
      name = (const char*)(*namestr);

      val = config->Get(String::New("mode"));
      if (doCreate) {
        if (val->IsUint32())
          mode = (mode_t)val->Uint32Value();
        else if (val->IsString()) {
          String::AsciiValue modestr(val->ToString());
          mode = (mode_t)strtoul((const char*)(*modestr), NULL, 8);
        } else {
          return ThrowException(Exception::TypeError(
              String::New("'mode' property must be a string or integer")));
        }
        flags |= O_CREAT;

        val = config->Get(String::New("exclusive"));
        if (val->IsBoolean() && val->BooleanValue() == true)
          flags |= O_EXCL;

        val = config->Get(String::New("maxmsgs"));
        if (val->IsUint32())
          obj->mqattrs.mq_maxmsg = val->Uint32Value();
        else
          obj->mqattrs.mq_maxmsg = 10;
        val = config->Get(String::New("msgsize"));
        if (val->IsUint32())
          obj->mqattrs.mq_msgsize = val->Uint32Value();
        else
          obj->mqattrs.mq_msgsize = 8192;
      }

      if (obj->mqdes != MQDES_INVALID)
        obj->close();

      if (doCreate)
        obj->mqdes = mq_open(name, flags, mode, &(obj->mqattrs));
      else
        obj->mqdes = mq_open(name, flags);

      if (obj->mqdes == MQDES_INVALID ||
          mq_getattr(obj->mqdes, &(obj->mqattrs)) == -1) {
        return ThrowException(Exception::Error(
            String::New(uv_strerror(uv_last_error(uv_default_loop())))));
      }

      if (obj->mqname) {
        free(obj->mqname);
        obj->mqname = NULL;
      } else {
        obj->Emit = Persistent<Function>::New(Local<Function>::Cast(
                                               obj->handle_->Get(emit_symbol)));
      }

      obj->mqname = strdup(name);

      obj->canread = !(obj->mqattrs.mq_curmsgs > 0);
      obj->canwrite = !(obj->mqattrs.mq_curmsgs < obj->mqattrs.mq_maxmsg);

      if (!obj->mqpollhandle)
        obj->mqpollhandle = new uv_poll_t;
      obj->mqpollhandle->data = obj;
      uv_poll_init(uv_default_loop(), obj->mqpollhandle, MQDES_TO_FD(obj->mqdes));
      uv_poll_start(obj->mqpollhandle, UV_READABLE | UV_WRITABLE, poll_cb);

      return Undefined();
    }

    static void poll_cb(uv_poll_t *handle, int status, int events) {
      HandleScope scope;
      assert(status == 0);

      PosixMQ* obj = (PosixMQ*)handle->data;

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      if ((events & UV_READABLE) && !obj->canread) {
        obj->canread = true;

        TryCatch try_catch;
        obj->Emit->Call(obj->handle_, 1, read_emit_argv);
        if (try_catch.HasCaught())
          FatalException(try_catch);
      } else if (!(events & UV_READABLE))
        obj->canread = false;

      if ((events & UV_WRITABLE) && !obj->canwrite) {
        obj->canwrite = true;
        TryCatch try_catch;
        obj->Emit->Call(obj->handle_, 1, write_emit_argv);
        if (try_catch.HasCaught())
          FatalException(try_catch);
      } else if (!(events & UV_WRITABLE))
        obj->canwrite = false;
    }

    static Handle<Value> Close(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());

      if (obj->mqdes == MQDES_INVALID) {
        return ThrowException(Exception::Error(
            String::New("Queue already closed")));
      }

      int r = obj->close();

      if (r == -1) {
        return ThrowException(Exception::Error(
            String::New(uv_strerror(uv_last_error(uv_default_loop())))));
      }

      return Undefined();
    }

    static Handle<Value> Unlink(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());

      if (!obj->mqname) {
        return ThrowException(Exception::Error(
            String::New("Nothing to unlink")));
      }

      if (mq_unlink((const char*)obj->mqname) == -1) {
        return ThrowException(Exception::Error(
            String::New(uv_strerror(uv_last_error(uv_default_loop())))));
      }

      if (obj->mqname) {
        free(obj->mqname);
        obj->mqname = NULL;
      }

      return Undefined();
    }

    static Handle<Value> Send(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());
      uint32_t priority = 0;
      bool ret = true;

      if (args.Length() < 1) {
        return ThrowException(Exception::TypeError(
            String::New("Expected at least 1 argument")));
      } else if (!Buffer::HasInstance(args[0])) {
        return ThrowException(Exception::TypeError(
            String::New("First argument must be a Buffer")));
      } else if (args.Length() >= 2) {
        if (args[1]->IsUint32() && args[1]->Uint32Value() < 32)
          priority = args[1]->Uint32Value();
        else {
          return ThrowException(Exception::TypeError(
              String::New("Second argument must be an integer 0 <= n < 32")));
        }
      }

      if (mq_send(obj->mqdes, Buffer::Data(args[0]->ToObject()),
                  Buffer::Length(args[0]->ToObject()), priority) == -1) {
        if (errno != EAGAIN) {
          return ThrowException(Exception::Error(
              String::New(uv_strerror(uv_last_error(uv_default_loop())))));
        }
        ret = false;
      }

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Boolean::New(ret));
    }

    static Handle<Value> Receive(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());
      ssize_t nBytes;
      uint32_t priority;
      bool retTuple = false;
      Local<Value> ret;

      if (args.Length() < 1) {
        return ThrowException(Exception::TypeError(
            String::New("Expected at least 1 argument")));
      } else if (!Buffer::HasInstance(args[0])) {
        return ThrowException(Exception::TypeError(
            String::New("First argument must be a Buffer")));
      } else if (args.Length() > 1)
        retTuple = args[1]->BooleanValue();

      Local<Object> buf = args[0]->ToObject();
      if ((nBytes = mq_receive(obj->mqdes, Buffer::Data(buf),
                               Buffer::Length(buf), &priority)) == -1) {
        if (errno != EAGAIN) {
          return ThrowException(Exception::Error(
              String::New(uv_strerror(uv_last_error(uv_default_loop())))));
        }
        ret = Local<Value>::New(Boolean::New(false));
      } else if (!retTuple)
        ret = Integer::New(nBytes);
      else {
        Local<Array> tuple = Array::New(2);
        tuple->Set(0, Integer::New(nBytes));
        tuple->Set(1, Integer::New(priority));
        ret = tuple;
      }

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(ret);
    }

    static Handle<Value> MsgsizeGetter (Local<String> property, const AccessorInfo& info) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(info.This());

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Integer::New(obj->mqattrs.mq_msgsize));
    }

    static Handle<Value> MaxmsgsGetter (Local<String> property, const AccessorInfo& info) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(info.This());

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Integer::New(obj->mqattrs.mq_maxmsg));
    }

    static Handle<Value> CurmsgsGetter (Local<String> property, const AccessorInfo& info) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(info.This());

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Integer::New(obj->mqattrs.mq_curmsgs));
    }

    static Handle<Value> IsfullGetter (Local<String> property, const AccessorInfo& info) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(info.This());

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Boolean::New(obj->mqattrs.mq_curmsgs == obj->mqattrs.mq_maxmsg));
    }

    static void Initialize(Handle<Object> target) {
      HandleScope scope;

      Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
      Local<String> name = String::NewSymbol("PosixMQ");

      constructor = Persistent<FunctionTemplate>::New(tpl);
      constructor->InstanceTemplate()->SetInternalFieldCount(1);
      constructor->SetClassName(name);

      NODE_SET_PROTOTYPE_METHOD(constructor, "open", Open);
      NODE_SET_PROTOTYPE_METHOD(constructor, "close", Close);
      NODE_SET_PROTOTYPE_METHOD(constructor, "push", Send);
      NODE_SET_PROTOTYPE_METHOD(constructor, "shift", Receive);
      NODE_SET_PROTOTYPE_METHOD(constructor, "unlink", Unlink);

      constructor->PrototypeTemplate()->SetAccessor(String::New("msgsize"),
                                                    MsgsizeGetter);
      constructor->PrototypeTemplate()->SetAccessor(String::New("maxmsgs"),
                                                    MaxmsgsGetter);
      constructor->PrototypeTemplate()->SetAccessor(String::New("curmsgs"),
                                                    CurmsgsGetter);
      constructor->PrototypeTemplate()->SetAccessor(String::New("isFull"),
                                                    IsfullGetter);
      emit_symbol = NODE_PSYMBOL("emit");
      read_emit_argv[0] = NODE_PSYMBOL("messages");
      write_emit_argv[0] = NODE_PSYMBOL("drain");
      target->Set(name, constructor->GetFunction());
    }
};

extern "C" {
  void init(Handle<Object> target) {
    HandleScope scope;
    PosixMQ::Initialize(target);
  }

  NODE_MODULE(posixmq, init);
}
<commit_msg>Added {} to constructor to compile on Ubuntu.<commit_after>#include <node.h>
#include <node_buffer.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <mqueue.h>

#if defined(__linux__)
#  define MQDES_TO_FD(mqdes) (int)(mqdes)
#elif defined(__FreeBSD__)
#  define MQDES_TO_FD(mqdes) __mq_oshandle(mqdes)
#endif

using namespace node;
using namespace v8;

static Persistent<FunctionTemplate> constructor;
static Persistent<String> emit_symbol;
static Persistent<Value> read_emit_argv[1];
static Persistent<Value> write_emit_argv[1];
static const mqd_t MQDES_INVALID = (mqd_t)-1;

class PosixMQ : public ObjectWrap {
  public:
    mqd_t mqdes;
    struct mq_attr mqattrs;
    uv_poll_t* mqpollhandle;
    char* mqname;
    Persistent<Function> Emit;
    bool canread;
    bool canwrite;

    PosixMQ() : mqpollhandle(NULL), mqdes(MQDES_INVALID), mqname(NULL),
                canread(false), canwrite(false) {};

    ~PosixMQ() {
      if (mqdes != MQDES_INVALID) {
        close();
        delete mqpollhandle;
        mqpollhandle = NULL;
      }
      if (mqname) {
        free(mqname);
        mqname = NULL;
      }
      Emit.Dispose();
      Emit.Clear();
    }

    int close() {
      int r;
      uv_poll_stop(mqpollhandle);
      uv_close((uv_handle_t *)mqpollhandle, on_close);
      r = mq_close(mqdes);
      mqdes = MQDES_INVALID;
      return r;
    }

    static void on_close (uv_handle_t *handle) {}

    static Handle<Value> New(const Arguments& args) {
      HandleScope scope;

      if (!args.IsConstructCall()) {
        return ThrowException(Exception::TypeError(
            String::New("Use `new` to create instances of this object.")));
      }

      PosixMQ* obj = new PosixMQ();
      obj->Wrap(args.This());

      return args.This();
    }

    static Handle<Value> Open(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());
      bool doCreate = false;
      int flags = O_RDWR | O_NONBLOCK;
      mode_t mode;
      const char* name;

      if (args.Length() != 1) {
        return ThrowException(Exception::TypeError(
            String::New("Expecting 1 argument")));
      }
      if (!args[0]->IsObject()) {
        return ThrowException(Exception::TypeError(
            String::New("Argument must be an object")));
      }

      Local<Object> config = args[0]->ToObject();
      Local<Value> val;

      if (!(val = config->Get(String::New("create")))->IsUndefined()) {
        if (!val->IsBoolean()) {
          return ThrowException(Exception::TypeError(
              String::New("'create' property must be a boolean")));
        }
        doCreate = val->BooleanValue();
      }

      val = config->Get(String::New("name"));
      if (!val->IsString()) {
        return ThrowException(Exception::TypeError(
            String::New("'name' property must be a string")));
      }
      String::AsciiValue namestr(val->ToString());
      name = (const char*)(*namestr);

      val = config->Get(String::New("mode"));
      if (doCreate) {
        if (val->IsUint32())
          mode = (mode_t)val->Uint32Value();
        else if (val->IsString()) {
          String::AsciiValue modestr(val->ToString());
          mode = (mode_t)strtoul((const char*)(*modestr), NULL, 8);
        } else {
          return ThrowException(Exception::TypeError(
              String::New("'mode' property must be a string or integer")));
        }
        flags |= O_CREAT;

        val = config->Get(String::New("exclusive"));
        if (val->IsBoolean() && val->BooleanValue() == true)
          flags |= O_EXCL;

        val = config->Get(String::New("maxmsgs"));
        if (val->IsUint32())
          obj->mqattrs.mq_maxmsg = val->Uint32Value();
        else
          obj->mqattrs.mq_maxmsg = 10;
        val = config->Get(String::New("msgsize"));
        if (val->IsUint32())
          obj->mqattrs.mq_msgsize = val->Uint32Value();
        else
          obj->mqattrs.mq_msgsize = 8192;
      }

      if (obj->mqdes != MQDES_INVALID)
        obj->close();

      if (doCreate)
        obj->mqdes = mq_open(name, flags, mode, &(obj->mqattrs));
      else
        obj->mqdes = mq_open(name, flags);

      if (obj->mqdes == MQDES_INVALID ||
          mq_getattr(obj->mqdes, &(obj->mqattrs)) == -1) {
        return ThrowException(Exception::Error(
            String::New(uv_strerror(uv_last_error(uv_default_loop())))));
      }

      if (obj->mqname) {
        free(obj->mqname);
        obj->mqname = NULL;
      } else {
        obj->Emit = Persistent<Function>::New(Local<Function>::Cast(
                                               obj->handle_->Get(emit_symbol)));
      }

      obj->mqname = strdup(name);

      obj->canread = !(obj->mqattrs.mq_curmsgs > 0);
      obj->canwrite = !(obj->mqattrs.mq_curmsgs < obj->mqattrs.mq_maxmsg);

      if (!obj->mqpollhandle)
        obj->mqpollhandle = new uv_poll_t;
      obj->mqpollhandle->data = obj;
      uv_poll_init(uv_default_loop(), obj->mqpollhandle, MQDES_TO_FD(obj->mqdes));
      uv_poll_start(obj->mqpollhandle, UV_READABLE | UV_WRITABLE, poll_cb);

      return Undefined();
    }

    static void poll_cb(uv_poll_t *handle, int status, int events) {
      HandleScope scope;
      assert(status == 0);

      PosixMQ* obj = (PosixMQ*)handle->data;

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      if ((events & UV_READABLE) && !obj->canread) {
        obj->canread = true;

        TryCatch try_catch;
        obj->Emit->Call(obj->handle_, 1, read_emit_argv);
        if (try_catch.HasCaught())
          FatalException(try_catch);
      } else if (!(events & UV_READABLE))
        obj->canread = false;

      if ((events & UV_WRITABLE) && !obj->canwrite) {
        obj->canwrite = true;
        TryCatch try_catch;
        obj->Emit->Call(obj->handle_, 1, write_emit_argv);
        if (try_catch.HasCaught())
          FatalException(try_catch);
      } else if (!(events & UV_WRITABLE))
        obj->canwrite = false;
    }

    static Handle<Value> Close(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());

      if (obj->mqdes == MQDES_INVALID) {
        return ThrowException(Exception::Error(
            String::New("Queue already closed")));
      }

      int r = obj->close();

      if (r == -1) {
        return ThrowException(Exception::Error(
            String::New(uv_strerror(uv_last_error(uv_default_loop())))));
      }

      return Undefined();
    }

    static Handle<Value> Unlink(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());

      if (!obj->mqname) {
        return ThrowException(Exception::Error(
            String::New("Nothing to unlink")));
      }

      if (mq_unlink((const char*)obj->mqname) == -1) {
        return ThrowException(Exception::Error(
            String::New(uv_strerror(uv_last_error(uv_default_loop())))));
      }

      if (obj->mqname) {
        free(obj->mqname);
        obj->mqname = NULL;
      }

      return Undefined();
    }

    static Handle<Value> Send(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());
      uint32_t priority = 0;
      bool ret = true;

      if (args.Length() < 1) {
        return ThrowException(Exception::TypeError(
            String::New("Expected at least 1 argument")));
      } else if (!Buffer::HasInstance(args[0])) {
        return ThrowException(Exception::TypeError(
            String::New("First argument must be a Buffer")));
      } else if (args.Length() >= 2) {
        if (args[1]->IsUint32() && args[1]->Uint32Value() < 32)
          priority = args[1]->Uint32Value();
        else {
          return ThrowException(Exception::TypeError(
              String::New("Second argument must be an integer 0 <= n < 32")));
        }
      }

      if (mq_send(obj->mqdes, Buffer::Data(args[0]->ToObject()),
                  Buffer::Length(args[0]->ToObject()), priority) == -1) {
        if (errno != EAGAIN) {
          return ThrowException(Exception::Error(
              String::New(uv_strerror(uv_last_error(uv_default_loop())))));
        }
        ret = false;
      }

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Boolean::New(ret));
    }

    static Handle<Value> Receive(const Arguments& args) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(args.This());
      ssize_t nBytes;
      uint32_t priority;
      bool retTuple = false;
      Local<Value> ret;

      if (args.Length() < 1) {
        return ThrowException(Exception::TypeError(
            String::New("Expected at least 1 argument")));
      } else if (!Buffer::HasInstance(args[0])) {
        return ThrowException(Exception::TypeError(
            String::New("First argument must be a Buffer")));
      } else if (args.Length() > 1)
        retTuple = args[1]->BooleanValue();

      Local<Object> buf = args[0]->ToObject();
      if ((nBytes = mq_receive(obj->mqdes, Buffer::Data(buf),
                               Buffer::Length(buf), &priority)) == -1) {
        if (errno != EAGAIN) {
          return ThrowException(Exception::Error(
              String::New(uv_strerror(uv_last_error(uv_default_loop())))));
        }
        ret = Local<Value>::New(Boolean::New(false));
      } else if (!retTuple)
        ret = Integer::New(nBytes);
      else {
        Local<Array> tuple = Array::New(2);
        tuple->Set(0, Integer::New(nBytes));
        tuple->Set(1, Integer::New(priority));
        ret = tuple;
      }

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(ret);
    }

    static Handle<Value> MsgsizeGetter (Local<String> property, const AccessorInfo& info) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(info.This());

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Integer::New(obj->mqattrs.mq_msgsize));
    }

    static Handle<Value> MaxmsgsGetter (Local<String> property, const AccessorInfo& info) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(info.This());

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Integer::New(obj->mqattrs.mq_maxmsg));
    }

    static Handle<Value> CurmsgsGetter (Local<String> property, const AccessorInfo& info) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(info.This());

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Integer::New(obj->mqattrs.mq_curmsgs));
    }

    static Handle<Value> IsfullGetter (Local<String> property, const AccessorInfo& info) {
      HandleScope scope;
      PosixMQ* obj = ObjectWrap::Unwrap<PosixMQ>(info.This());

      mq_getattr(obj->mqdes, &(obj->mqattrs));

      return scope.Close(Boolean::New(obj->mqattrs.mq_curmsgs == obj->mqattrs.mq_maxmsg));
    }

    static void Initialize(Handle<Object> target) {
      HandleScope scope;

      Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
      Local<String> name = String::NewSymbol("PosixMQ");

      constructor = Persistent<FunctionTemplate>::New(tpl);
      constructor->InstanceTemplate()->SetInternalFieldCount(1);
      constructor->SetClassName(name);

      NODE_SET_PROTOTYPE_METHOD(constructor, "open", Open);
      NODE_SET_PROTOTYPE_METHOD(constructor, "close", Close);
      NODE_SET_PROTOTYPE_METHOD(constructor, "push", Send);
      NODE_SET_PROTOTYPE_METHOD(constructor, "shift", Receive);
      NODE_SET_PROTOTYPE_METHOD(constructor, "unlink", Unlink);

      constructor->PrototypeTemplate()->SetAccessor(String::New("msgsize"),
                                                    MsgsizeGetter);
      constructor->PrototypeTemplate()->SetAccessor(String::New("maxmsgs"),
                                                    MaxmsgsGetter);
      constructor->PrototypeTemplate()->SetAccessor(String::New("curmsgs"),
                                                    CurmsgsGetter);
      constructor->PrototypeTemplate()->SetAccessor(String::New("isFull"),
                                                    IsfullGetter);
      emit_symbol = NODE_PSYMBOL("emit");
      read_emit_argv[0] = NODE_PSYMBOL("messages");
      write_emit_argv[0] = NODE_PSYMBOL("drain");
      target->Set(name, constructor->GetFunction());
    }
};

extern "C" {
  void init(Handle<Object> target) {
    HandleScope scope;
    PosixMQ::Initialize(target);
  }

  NODE_MODULE(posixmq, init);
}
<|endoftext|>


<commit_before>/*
 * File:  trigger_data.cpp
 * Copyright (C) 2006 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
 */

#include <string.h>
#include "tr/triggers/triggers_data.h"
#include "tr/triggers/triggers_utils.h"
#include "common/errdbg/exceptions.h"
#include "tr/crmutils/node_utils.h"
#include "tr/vmm/vmm.h"
#include "tr/executor/base/tuple.h"
#include "tr/log/log.h"
#include "tr/structures/schema.h"
#include "tr/executor/por2qep/por2qep.h"
#include "tr/executor/base/dm_accessors.h"

//using namespace std;

//Global
qep_parameters_vec* qep_parameters = NULL;

pers_sset<trigger_cell,unsigned short> *triggerdata;
USemaphore trigger_sem;//SEMAPHORE!!!

static bool triggers_initialized = false;

//inits metadata library
void triggers_on_session_begin(pers_sset<trigger_cell,unsigned short> * _triggerdata_)
{
    triggerdata = _triggerdata_;
	//SEMAPHORE INIT SECTION
	if (USemaphoreOpen(&trigger_sem, TRIGGER_SEMAPHORE_STR, __sys_call_error) != 0)
        throw USER_EXCEPTION2(SE4012, "TRIGGER_SEMAPHORE_STR");

    triggers_initialized = true;
}

void triggers_on_session_end()
{
    if (!triggers_initialized) return;
	//SEMAPHORE RELEASE SECTION
    if (USemaphoreClose(trigger_sem, __sys_call_error) != 0)
        throw USER_EXCEPTION2(SE4013, "TRIGGER_SEMAPHORE_STR");
    triggers_initialized = false;
}

void triggers_on_statement_begin()
{
    current_nesting_level = 0;
}

void triggers_on_statement_end()
{
    clear_nested_updates_track_map();
    clear_built_trigger_actions_map();
    current_nesting_level = 0;
}

pers_sset<trigger_cell,unsigned short>::pers_sset_entry* search_triggerdata_cell(const char *trigger_title)
{
	return triggerdata->get(trigger_title,NULL);
}

bool trigger_cell::fits_to_trigger(schema_node* snode)
{
	t_scmnodes objs=execute_abs_path_expr(snode->root,trigger_path);
	t_scmnodes::iterator it=objs.begin();
	while (it!=objs.end())
	{
		if (*it==snode)
			return true;
		it++;
	}
	return false;
}
bool trigger_cell::fits_to_trigger_path_to_parent(schema_node* parent)
{
	t_scmnodes objs=execute_abs_path_expr(parent->root,path_to_parent);
	t_scmnodes::iterator it=objs.begin();
	while (it!=objs.end())
	{
		if (*it==parent)
			return true;
		it++;
	}
	return false;
}
void inline free_triggerdata_cell(pers_sset<trigger_cell,unsigned short>::pers_sset_entry* entry)
{
	trigger_cell* trc=entry->obj;
	triggerdata->rb_delete(entry);
	if (trc->trigger_title!=NULL)
		scm_free(trc->trigger_title,true);
    if (trc->trigger_path!=NULL)
        delete_PathExpr(trc->trigger_path);
    if (trc->doc_name!=NULL)
        scm_free(trc->doc_name,true);
    trigger_action_cell *trac=trc->trigger_action;
    trigger_action_cell *trac2=NULL;
    while(trac!=NULL)
    {
        scm_free(trac->statement,true);
        trac2=trac->next;
        scm_free(trac, true);
        trac=trac2;
    }
	if (trc->path_to_parent!=NULL)
    {
		delete_PathExpr(trc->path_to_parent);
        scm_free(trc->innode.name,true);
    }
    scm_free(trc,true);
}
trigger_cell* trigger_cell::create_trigger (enum trigger_time time, enum trigger_event event, PathExpr *trigger_path,  enum trigger_granularity gran, scheme_list* action, inserting_node innode, PathExpr *path_to_parent, doc_schema_node* schemaroot,const char * trigger_title, const char* doc_name,bool is_doc)
{
	// I. Create and fill new trigger cell
	trigger_sem_down();
	if (search_triggerdata_cell(trigger_title)!=NULL)
	{
		trigger_sem_up();
		throw USER_EXCEPTION(SE3200);
	}
	down_concurrent_micro_ops_number();
	trigger_cell* trc=(trigger_cell*)scm_malloc(sizeof(trigger_cell),true);
	trc->schemaroot = schemaroot;
	schemaroot->create_trigger(trc);
	trc->trigger_path = trigger_path;
	trc->trigger_event = event;
    trc->trigger_time = time;
    trc->trigger_granularity = gran;
    trc->trigger_action = (trigger_action_cell*)scm_malloc(sizeof(trigger_action_cell),true);
    trigger_action_cell* trac = trc->trigger_action;
    for(int i = 0; i < action->size(); i++)
    {
		if(strstr(action->at(i).internal.str, "PPQueryRoot") != NULL) // this is a query
        {
            trac->statement = (char*)scm_malloc(strlen(action->at(i).internal.str)+1,true);
            strncpy(trac->statement,action->at(i).internal.str+37, strlen(action->at(i).internal.str)-2);
            trac->cxt_size = atoi(action->at(i).internal.str+35);
// FIXME cxt_size for trigger statements must be extracted in scheme part
//            trac->cxt_size = atoi(action->at(i+1).internal.num);
        }
        else  //this is update
        {
            trac->statement = (char*)scm_malloc(strlen(action->at(i).internal.str)+1,true);
            strcpy(trac->statement,action->at(i).internal.str);
        }
        if(i==action->size()-1)
            trac->next = NULL;
        else
            trac->next = (trigger_action_cell*)scm_malloc(sizeof(trigger_action_cell),true);
        trac = trac->next;
    }
    // if the trigger is on before insert and statement level
    if((trc->trigger_event == TRIGGER_INSERT_EVENT) &&
       (trc->trigger_time == TRIGGER_BEFORE) &&
       (trc->trigger_granularity == TRIGGER_FOR_EACH_NODE)&&
       (path_to_parent))
    {
        trc->path_to_parent = path_to_parent;
        trc->innode.name = (char*)scm_malloc(strlen(innode.name)+1,true);
        strcpy(trc->innode.name,innode.name);
        trc->innode.type = innode.type;
    }
	else
	{
		trc->path_to_parent = NULL;
		trc->innode.name = NULL;
	}
	trc->trigger_title=(char*)scm_malloc(strlen(trigger_title)+1,true);
	strcpy(trc->trigger_title,trigger_title);
	trc->doc_name=(char*)scm_malloc(strlen(doc_name)+1,true);
	strcpy(trc->doc_name,doc_name);
	trc->is_doc=is_doc;

	triggerdata->put(trc);
	trigger_sem_up();
//    hl_logical_log_ft_index(object_path, it,(char *) index_title, doc_name,is_doc,idc->custom_tree,true);

	// ALGORITHM: setting up trigger over discriptive scheme
	//II. Execute abs path (object_path) on the desriptive schema
	t_scmnodes sobj = execute_abs_path_expr(schemaroot, trigger_path);
	//III. For each schema node found (sn_obj)
	std::vector<xptr> start_nodes;
	for (int i = 0; i < sobj.size(); i++)
	{
		sobj[i]->add_trigger(trc);
	}

   	up_concurrent_micro_ops_number();

	return trc;
}
void trigger_cell::delete_trigger (const char *trigger_title)
{
	trigger_sem_down();
	pers_sset<trigger_cell,unsigned short>::pers_sset_entry* trc=search_triggerdata_cell(trigger_title);
	if (trc!=NULL)
	{
		down_concurrent_micro_ops_number();
//		hl_logical_log_ft_index((idc->obj)->object,(idc->obj)->ftype,(idc->obj)->index_title,(idc->obj)->doc_name,(idc->obj)->is_doc,(idc->obj)->custom_tree,false);
		trigger_cell* tc=trc->obj;
		doc_schema_node* sm=(trc->obj)->schemaroot;
		free_triggerdata_cell(trc);
   		sm->delete_trigger(tc);
		trigger_sem_up();
		up_concurrent_micro_ops_number();
	}
	else
		trigger_sem_up();
}
trigger_cell* trigger_cell::find_trigger(const char* title)
{
    trigger_sem_down();
	pers_sset<trigger_cell,unsigned short>::pers_sset_entry* trc=search_triggerdata_cell(title);
	if (trc==NULL)
	{
		trigger_sem_up();
		return NULL;
	}
	else
	{
		trigger_sem_up();
		return trc->obj;
	}
}
xptr trigger_cell::execute_trigger_action(xptr parameter_new, xptr parameter_old, xptr parameter_where)
{
   xptr res_xptr;
   se_nullostream nulls;
   PPQueryEssence* qep_tree = NULL;
   qep_subtree* qep_subtree = NULL;
   bool is_qep_opened = false, is_subqep_opened = false, is_qep_built = false, is_subqep_built = false;
   std::vector<built_trigger_action> built_trigger_actions_vec;
   typedef std::pair< std::string, std::vector<built_trigger_action> > trigger_actions_pair;

   current_nesting_level++;
   if(current_nesting_level > TRIGGER_MAX_CASCADING_LEVEL) throw USER_EXCEPTION2(SE3206,trigger_title);

    built_trigger_actions_map::iterator mapIter;
   	mapIter = built_trigger_actions.find(std::string(trigger_title));
	if ( mapIter == built_trigger_actions.end() )            // trigger action has not been built yet -> build it and store into the map
	{
        std::pair<built_trigger_actions_map::iterator, bool> mapPair;
        trigger_action_cell* trac = trigger_action;
        try
        {
			built_trigger_action bta;
            is_qep_built = is_subqep_built = false;
	        qep_parameters = &(bta.parameters);
            while(trac!=NULL)
        	{
				if(strstr(trac->statement, "query") == NULL)
				{
					bta.action_qep_subtree = NULL;
					qep_tree = bta.action_qep_tree = build_qep(trac->statement, nulls, xml);
					is_qep_built = true;
					qep_tree->open();
					is_qep_opened = true;
					built_trigger_actions_vec.push_back(bta);
					trac = trac->next;
				}
				else
				{
       				bta.action_qep_tree = NULL;
           			qep_subtree = bta.action_qep_subtree = build_qep(trac->statement, trac->cxt_size);
					is_subqep_built = true;
					qep_subtree->tree.op->open();
					is_subqep_opened = true;
					built_trigger_actions_vec.push_back(bta);
				}
	        }
        }
        catch(SednaUserException &e) {
        if (is_qep_built)
	        delete_qep(qep_tree);
        if (is_subqep_built)
            delete_qep(qep_subtree);
        throw e;}

        mapPair = built_trigger_actions.insert(trigger_actions_pair(std::string(trigger_title), built_trigger_actions_vec));
        mapIter = mapPair.first;
    }

     //executing built actions
     try
     {
         int i = 0;
         for(i = 0; i < mapIter->second.size()-1; i++)
         {
          	qep_tree = mapIter->second.at(i).action_qep_tree;
            qep_parameters = &(mapIter->second.at(i).parameters);
   	        set_action_parameters(parameter_new, parameter_old, parameter_where, trigger_granularity, std::string(trigger_title));
           	//is_qep_opened = true;
            if(qep_tree->is_update())
   	            qep_tree->execute();
       	}
       	qep_subtree = mapIter->second.at(i).action_qep_subtree;
        qep_parameters = &(mapIter->second.at(i).parameters);
   	    set_action_parameters(parameter_new, parameter_old, parameter_where, trigger_granularity, std::string(trigger_title));
//        is_subqep_opened = true;
		tuple t = tuple(1);
		qep_subtree->tree.op->next(t);

		if ((trigger_time == TRIGGER_BEFORE)&&(trigger_granularity == TRIGGER_FOR_EACH_NODE))
			if (!t.cells[0].is_node())
				res_xptr = XNULL;
		   	else
			{
				res_xptr = t.cells[0].get_node();
				CHECKP(res_xptr);
			}
		else res_xptr = XNULL;

		// retrieve all items to make the qep_subtree usable next time
		while(!t.is_eos())
			qep_subtree->tree.op->next(t);
	}
    catch (SednaUserException &e) {
        throw e;
    }

   current_nesting_level--;
   return res_xptr;
}

<commit_msg>trigger action can contain queries and updates in any order<commit_after>/*
 * File:  trigger_data.cpp
 * Copyright (C) 2006 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
 */

#include <string.h>
#include "tr/triggers/triggers_data.h"
#include "tr/triggers/triggers_utils.h"
#include "common/errdbg/exceptions.h"
#include "tr/crmutils/node_utils.h"
#include "tr/vmm/vmm.h"
#include "tr/executor/base/tuple.h"
#include "tr/log/log.h"
#include "tr/structures/schema.h"
#include "tr/executor/por2qep/por2qep.h"
#include "tr/executor/base/dm_accessors.h"

//using namespace std;

//Global
qep_parameters_vec* qep_parameters = NULL;

pers_sset<trigger_cell,unsigned short> *triggerdata;
USemaphore trigger_sem;//SEMAPHORE!!!

static bool triggers_initialized = false;

//inits metadata library
void triggers_on_session_begin(pers_sset<trigger_cell,unsigned short> * _triggerdata_)
{
    triggerdata = _triggerdata_;
	//SEMAPHORE INIT SECTION
	if (USemaphoreOpen(&trigger_sem, TRIGGER_SEMAPHORE_STR, __sys_call_error) != 0)
        throw USER_EXCEPTION2(SE4012, "TRIGGER_SEMAPHORE_STR");

    triggers_initialized = true;
}

void triggers_on_session_end()
{
    if (!triggers_initialized) return;
	//SEMAPHORE RELEASE SECTION
    if (USemaphoreClose(trigger_sem, __sys_call_error) != 0)
        throw USER_EXCEPTION2(SE4013, "TRIGGER_SEMAPHORE_STR");
    triggers_initialized = false;
}

void triggers_on_statement_begin()
{
    current_nesting_level = 0;
}

void triggers_on_statement_end()
{
    clear_nested_updates_track_map();
    clear_built_trigger_actions_map();
    current_nesting_level = 0;
}

pers_sset<trigger_cell,unsigned short>::pers_sset_entry* search_triggerdata_cell(const char *trigger_title)
{
	return triggerdata->get(trigger_title,NULL);
}

bool trigger_cell::fits_to_trigger(schema_node* snode)
{
	t_scmnodes objs=execute_abs_path_expr(snode->root,trigger_path);
	t_scmnodes::iterator it=objs.begin();
	while (it!=objs.end())
	{
		if (*it==snode)
			return true;
		it++;
	}
	return false;
}
bool trigger_cell::fits_to_trigger_path_to_parent(schema_node* parent)
{
	t_scmnodes objs=execute_abs_path_expr(parent->root,path_to_parent);
	t_scmnodes::iterator it=objs.begin();
	while (it!=objs.end())
	{
		if (*it==parent)
			return true;
		it++;
	}
	return false;
}
void inline free_triggerdata_cell(pers_sset<trigger_cell,unsigned short>::pers_sset_entry* entry)
{
	trigger_cell* trc=entry->obj;
	triggerdata->rb_delete(entry);
	if (trc->trigger_title!=NULL)
		scm_free(trc->trigger_title,true);
    if (trc->trigger_path!=NULL)
        delete_PathExpr(trc->trigger_path);
    if (trc->doc_name!=NULL)
        scm_free(trc->doc_name,true);
    trigger_action_cell *trac=trc->trigger_action;
    trigger_action_cell *trac2=NULL;
    while(trac!=NULL)
    {
        scm_free(trac->statement,true);
        trac2=trac->next;
        scm_free(trac, true);
        trac=trac2;
    }
	if (trc->path_to_parent!=NULL)
    {
		delete_PathExpr(trc->path_to_parent);
        scm_free(trc->innode.name,true);
    }
    scm_free(trc,true);
}
trigger_cell* trigger_cell::create_trigger (enum trigger_time time, enum trigger_event event, PathExpr *trigger_path,  enum trigger_granularity gran, scheme_list* action, inserting_node innode, PathExpr *path_to_parent, doc_schema_node* schemaroot,const char * trigger_title, const char* doc_name,bool is_doc)
{
	// I. Create and fill new trigger cell
	trigger_sem_down();
	if (search_triggerdata_cell(trigger_title)!=NULL)
	{
		trigger_sem_up();
		throw USER_EXCEPTION(SE3200);
	}
	down_concurrent_micro_ops_number();
	trigger_cell* trc=(trigger_cell*)scm_malloc(sizeof(trigger_cell),true);
	trc->schemaroot = schemaroot;
	schemaroot->create_trigger(trc);
	trc->trigger_path = trigger_path;
	trc->trigger_event = event;
    trc->trigger_time = time;
    trc->trigger_granularity = gran;
    trc->trigger_action = (trigger_action_cell*)scm_malloc(sizeof(trigger_action_cell),true);
    trigger_action_cell* trac = trc->trigger_action;
    for(int i = 0; i < action->size(); i++)
    {
		if(strstr(action->at(i).internal.str, "PPQueryRoot") != NULL) // this is a query
        {
            trac->statement = (char*)scm_malloc(strlen(action->at(i).internal.str)+1,true);
            strncpy(trac->statement,action->at(i).internal.str+37, strlen(action->at(i).internal.str)-2);
            trac->cxt_size = atoi(action->at(i).internal.str+35);
// FIXME cxt_size for trigger statements must be extracted in scheme part
//            trac->cxt_size = atoi(action->at(i+1).internal.num);
        }
        else  //this is update
        {
            trac->statement = (char*)scm_malloc(strlen(action->at(i).internal.str)+1,true);
            strcpy(trac->statement,action->at(i).internal.str);
        }
        if(i==action->size()-1)
            trac->next = NULL;
        else
            trac->next = (trigger_action_cell*)scm_malloc(sizeof(trigger_action_cell),true);
        trac = trac->next;
    }
    // if the trigger is on before insert and statement level
    if((trc->trigger_event == TRIGGER_INSERT_EVENT) &&
       (trc->trigger_time == TRIGGER_BEFORE) &&
       (trc->trigger_granularity == TRIGGER_FOR_EACH_NODE)&&
       (path_to_parent))
    {
        trc->path_to_parent = path_to_parent;
        trc->innode.name = (char*)scm_malloc(strlen(innode.name)+1,true);
        strcpy(trc->innode.name,innode.name);
        trc->innode.type = innode.type;
    }
	else
	{
		trc->path_to_parent = NULL;
		trc->innode.name = NULL;
	}
	trc->trigger_title=(char*)scm_malloc(strlen(trigger_title)+1,true);
	strcpy(trc->trigger_title,trigger_title);
	trc->doc_name=(char*)scm_malloc(strlen(doc_name)+1,true);
	strcpy(trc->doc_name,doc_name);
	trc->is_doc=is_doc;

	triggerdata->put(trc);
	trigger_sem_up();
//    hl_logical_log_ft_index(object_path, it,(char *) index_title, doc_name,is_doc,idc->custom_tree,true);

	// ALGORITHM: setting up trigger over discriptive scheme
	//II. Execute abs path (object_path) on the desriptive schema
	t_scmnodes sobj = execute_abs_path_expr(schemaroot, trigger_path);
	//III. For each schema node found (sn_obj)
	std::vector<xptr> start_nodes;
	for (int i = 0; i < sobj.size(); i++)
	{
		sobj[i]->add_trigger(trc);
	}

   	up_concurrent_micro_ops_number();

	return trc;
}
void trigger_cell::delete_trigger (const char *trigger_title)
{
	trigger_sem_down();
	pers_sset<trigger_cell,unsigned short>::pers_sset_entry* trc=search_triggerdata_cell(trigger_title);
	if (trc!=NULL)
	{
		down_concurrent_micro_ops_number();
//		hl_logical_log_ft_index((idc->obj)->object,(idc->obj)->ftype,(idc->obj)->index_title,(idc->obj)->doc_name,(idc->obj)->is_doc,(idc->obj)->custom_tree,false);
		trigger_cell* tc=trc->obj;
		doc_schema_node* sm=(trc->obj)->schemaroot;
		free_triggerdata_cell(trc);
   		sm->delete_trigger(tc);
		trigger_sem_up();
		up_concurrent_micro_ops_number();
	}
	else
		trigger_sem_up();
}
trigger_cell* trigger_cell::find_trigger(const char* title)
{
    trigger_sem_down();
	pers_sset<trigger_cell,unsigned short>::pers_sset_entry* trc=search_triggerdata_cell(title);
	if (trc==NULL)
	{
		trigger_sem_up();
		return NULL;
	}
	else
	{
		trigger_sem_up();
		return trc->obj;
	}
}
xptr trigger_cell::execute_trigger_action(xptr parameter_new, xptr parameter_old, xptr parameter_where)
{
   xptr res_xptr;
   se_nullostream nulls;
   PPQueryEssence* qep_tree = NULL;
   qep_subtree* qep_subtree = NULL;
   bool is_qep_opened = false, is_subqep_opened = false, is_qep_built = false, is_subqep_built = false;
   std::vector<built_trigger_action> built_trigger_actions_vec;
   typedef std::pair< std::string, std::vector<built_trigger_action> > trigger_actions_pair;

   current_nesting_level++;
   if(current_nesting_level > TRIGGER_MAX_CASCADING_LEVEL) throw USER_EXCEPTION2(SE3206,trigger_title);

    built_trigger_actions_map::iterator mapIter;
   	mapIter = built_trigger_actions.find(std::string(trigger_title));
	if ( mapIter == built_trigger_actions.end() )            // trigger action has not been built yet -> build it and store into the map
	{
        std::pair<built_trigger_actions_map::iterator, bool> mapPair;
        trigger_action_cell* trac = trigger_action;
        try
        {
			built_trigger_action bta;
            is_qep_built = is_subqep_built = false;
	        qep_parameters = &(bta.parameters);
            while(trac!=NULL)
        	{
				if(strstr(trac->statement, "query") != NULL)
				{
					bta.action_qep_subtree = NULL;
					qep_tree = bta.action_qep_tree = build_qep(trac->statement, nulls, xml);
					is_qep_built = true;
					qep_tree->open();
					is_qep_opened = true;
					built_trigger_actions_vec.push_back(bta);
				}
				else
				{
       				bta.action_qep_tree = NULL;
           			qep_subtree = bta.action_qep_subtree = build_qep(trac->statement, trac->cxt_size);
					is_subqep_built = true;
					qep_subtree->tree.op->open();
					is_subqep_opened = true;
					built_trigger_actions_vec.push_back(bta);
				}
				trac = trac->next;
	        }
        }
        catch(SednaUserException &e) {
        if (is_qep_built)
	        delete_qep(qep_tree);
        if (is_subqep_built)
            delete_qep(qep_subtree);
        throw e;}

        mapPair = built_trigger_actions.insert(trigger_actions_pair(std::string(trigger_title), built_trigger_actions_vec));
        mapIter = mapPair.first;
    }

     //executing built actions
     try
     {
         int i = 0;
         int action_returns_value = ((trigger_time == TRIGGER_BEFORE)&&(trigger_granularity == TRIGGER_FOR_EACH_NODE)) ? 1 : 0;
         for(i = 0; i < mapIter->second.size()-action_returns_value; i++)
         {
             if(mapIter->second.at(i).action_qep_tree)
             {
                 qep_tree = mapIter->second.at(i).action_qep_tree;
                 qep_parameters = &(mapIter->second.at(i).parameters);
	 			 set_action_parameters(parameter_new, parameter_old, parameter_where, trigger_granularity, std::string(trigger_title));
           	     if(qep_tree->is_update())
   	             qep_tree->execute();
             }
             /*else
             {
                 qep_subtree = mapIter->second.at(i).action_qep_subtree;
                 qep_parameters = &(mapIter->second.at(i).parameters);
                 set_action_parameters(parameter_new, parameter_old, parameter_where, trigger_granularity, std::string(trigger_title));
				 tuple t = tuple(1);
		   		 qep_subtree->tree.op->next(t);
             }*/
		}
		if (action_returns_value)
        {
            qep_subtree = mapIter->second.at(i).action_qep_subtree;
            qep_parameters = &(mapIter->second.at(i).parameters);
            set_action_parameters(parameter_new, parameter_old, parameter_where, trigger_granularity, std::string(trigger_title));
			tuple t = tuple(1);
		   	qep_subtree->tree.op->next(t);
			if (!t.cells[0].is_node())
				res_xptr = XNULL;
		   	else
			{
				res_xptr = t.cells[0].get_node();
				CHECKP(res_xptr);
			}
       		// retrieve all items to make the qep_subtree usable next time
			while(!t.is_eos())
				qep_subtree->tree.op->next(t);
        }
		else res_xptr = XNULL;

	}
    catch (SednaUserException &e) {
        throw e;
    }

   current_nesting_level--;
   return res_xptr;
}

<|endoftext|>


<commit_before>#include "OpenGLTexture.h"

#include "TextureRef.h"
#include "Image.h"

#define GL_GLEXT_PROTOTYPES

#if defined __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#elif (defined GL_ES)
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
#define GL_GLEXT_PROTOTYPES

#ifdef _WIN32
#include <GL/glew.h>
#include <windows.h>
#endif

#include <GL/gl.h>

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif

#endif

#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;

static bool checkGLError(const std::string & message) {
  GLenum errLast = GL_NO_ERROR;
  bool has_errors = false;
  for ( ;; ) {
    GLenum err = glGetError();
    if ( err == GL_NO_ERROR ) {
      break;
    }

    // normally the error is reset by the call to glGetError() but if
    // glGetError() itself returns an error, we risk looping forever here
    // so check that we get a different error than the last time
    if ( err == errLast ) {
      cerr << "OpenGL error state couldn't be reset.\n";
      break;
    }

    errLast = err;

    cerr << message << ": OpenGL error " << err << "\n";
    // assert(0);
    has_errors = true;
  }

  return has_errors;
}

static GLenum getOpenGLInternalFormat(InternalFormat internal_format) {
  switch (internal_format) {
  case RG8: return GL_RG8;
  case RGB565: return GL_RGB565;
  case RGBA4: return GL_RGBA4;
  case RGBA8: return GL_RGBA8;
#ifdef __linux__
  case COMPRESSED_RG: return GL_RG8;
  case COMPRESSED_RGB: return GL_RGB5;
  case COMPRESSED_RGBA: return GL_RGBA8;
#else
  case COMPRESSED_RG: return GL_COMPRESSED_RG11_EAC;
  case COMPRESSED_RGB:
      assert(0);
      return GL_COMPRESSED_RGB8_ETC2;
      // return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
  case COMPRESSED_RGBA:
      // assert(0);
      // return GL_COMPRESSED_RGBA8_ETC2_EAC;
      return GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
#endif
  case LUMINANCE_ALPHA: return GL_RG8;
  }
  return 0;
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateData(const void * buffer) {
  updateData(buffer, 0, 0, getActualWidth(), getActualHeight());
}

void
OpenGLTexture::updateData(const void * buffer, unsigned int x, unsigned int y, unsigned int width, unsigned int height) {
  checkGLError("error before texture update");

  assert(buffer);

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, getOpenGLInternalFormat(getInternalFormat()), getActualWidth(), getActualHeight());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));
  }

  if (getInternalFormat() == LUMINANCE_ALPHA) {
    cerr << "trying to update luminance texture" << endl;
    Image tmp_image(width, height, (const unsigned char *)buffer, ImageFormat::RGBA32);
    auto tmp_image2 = tmp_image.changeFormat(ImageFormat::LUMALPHA8);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RG, GL_UNSIGNED_BYTE, tmp_image2->getData());
  } else if (getInternalFormat() == RGB565) {
    Image tmp_image(width, height, (const unsigned char *)buffer, ImageFormat::RGBA32);
    auto tmp_image2 = tmp_image.changeFormat(ImageFormat::RGB565);
    cerr << "trying to update rgb565 texture, b1 = " << buffer << ", b2 = " << tmp_image2->getData() << ", x = " << x << ", y = " << y << ", w = " << width << ", h = " << height << ", mm = " << has_mipmaps << endl;
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tmp_image2->getData());
  } else {
    cerr << "trying to update rgba texture" << endl;
#ifdef __APPLE__
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
#else
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
#endif
  }
  if (has_mipmaps) {
    glGenerateMipmap(GL_TEXTURE_2D);
  }

  glBindTexture(GL_TEXTURE_2D, 0);

  checkGLError("Failed to update texture");
}

void
OpenGLTexture::releaseTextures() {
  // cerr << "DELETING TEXTURES: " << OpenGLTexture::getFreedTextures().size() << "/" << OpenGLTexture::getNumTextures() << endl;

  for (vector<unsigned int>::const_iterator it = freed_textures.begin(); it != freed_textures.end(); it++) {
    GLuint texid = *it;
    glDeleteTextures(1, &texid);
  }
  freed_textures.clear();
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}
<commit_msg>fix debug prints<commit_after>#include "OpenGLTexture.h"

#include "TextureRef.h"
#include "Image.h"

#define GL_GLEXT_PROTOTYPES

#if defined __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#elif (defined GL_ES)
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
#define GL_GLEXT_PROTOTYPES

#ifdef _WIN32
#include <GL/glew.h>
#include <windows.h>
#endif

#include <GL/gl.h>

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif

#endif

#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;

static bool checkGLError(const std::string & message) {
  GLenum errLast = GL_NO_ERROR;
  bool has_errors = false;
  for ( ;; ) {
    GLenum err = glGetError();
    if ( err == GL_NO_ERROR ) {
      break;
    }

    // normally the error is reset by the call to glGetError() but if
    // glGetError() itself returns an error, we risk looping forever here
    // so check that we get a different error than the last time
    if ( err == errLast ) {
      cerr << "OpenGL error state couldn't be reset.\n";
      break;
    }

    errLast = err;

    cerr << message << ": OpenGL error " << err << "\n";
    // assert(0);
    has_errors = true;
  }

  return has_errors;
}

static GLenum getOpenGLInternalFormat(InternalFormat internal_format) {
  switch (internal_format) {
  case RG8: return GL_RG8;
  case RGB565: return GL_RGB565;
  case RGBA4: return GL_RGBA4;
  case RGBA8: return GL_RGBA8;
#ifdef __linux__
  case COMPRESSED_RG: return GL_RG8;
  case COMPRESSED_RGB: return GL_RGB5;
  case COMPRESSED_RGBA: return GL_RGBA8;
#else
  case COMPRESSED_RG: return GL_COMPRESSED_RG11_EAC;
  case COMPRESSED_RGB:
      assert(0);
      return GL_COMPRESSED_RGB8_ETC2;
      // return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
  case COMPRESSED_RGBA:
      // assert(0);
      // return GL_COMPRESSED_RGBA8_ETC2_EAC;
      return GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
#endif
  case LUMINANCE_ALPHA: return GL_RG8;
  }
  return 0;
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateData(const void * buffer) {
  updateData(buffer, 0, 0, getActualWidth(), getActualHeight());
}

void
OpenGLTexture::updateData(const void * buffer, unsigned int x, unsigned int y, unsigned int width, unsigned int height) {
  checkGLError("error before texture update");

  assert(buffer);

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, getOpenGLInternalFormat(getInternalFormat()), getActualWidth(), getActualHeight());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));
  }

  if (getInternalFormat() == LUMINANCE_ALPHA) {
    cerr << "trying to update luminance texture" << endl;
    Image tmp_image(width, height, (const unsigned char *)buffer, ImageFormat::RGBA32);
    auto tmp_image2 = tmp_image.changeFormat(ImageFormat::LUMALPHA8);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RG, GL_UNSIGNED_BYTE, tmp_image2->getData());
  } else if (getInternalFormat() == RGB565) {
    Image tmp_image(width, height, (const unsigned char *)buffer, ImageFormat::RGBA32);
    auto tmp_image2 = tmp_image.changeFormat(ImageFormat::RGB565);
    cerr << "trying to update rgb565 texture, b1 = " << (void*)buffer << ", b2 = " << (void*)tmp_image2->getData() << ", x = " << x << ", y = " << y << ", w = " << width << ", h = " << height << ", mm = " << has_mipmaps << endl;
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tmp_image2->getData());
  } else {
    cerr << "trying to update rgba texture" << endl;
#ifdef __APPLE__
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
#else
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
#endif
  }
  if (has_mipmaps) {
    glGenerateMipmap(GL_TEXTURE_2D);
  }

  glBindTexture(GL_TEXTURE_2D, 0);

  checkGLError("Failed to update texture");
}

void
OpenGLTexture::releaseTextures() {
  // cerr << "DELETING TEXTURES: " << OpenGLTexture::getFreedTextures().size() << "/" << OpenGLTexture::getNumTextures() << endl;

  for (vector<unsigned int>::const_iterator it = freed_textures.begin(); it != freed_textures.end(); it++) {
    GLuint texid = *it;
    glDeleteTextures(1, &texid);
  }
  freed_textures.clear();
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}
<|endoftext|>


<commit_before>#include <boost/python.hpp>
#include <boost/python/exception_translator.hpp>
#include "cimage.h"
#include "cproc.h"
#include "gil.h"
#include "except.h"
#include "bitmap.h"

using namespace boost::python;

class CimageWrapper
    : public Cimage
    , public wrapper<Cimage>
{
public:
    CimageWrapper(size_t width, size_t height)
        : Cimage(width, height)
    {

    }

public:
    void info()
    {
        ScopedPythonGILLock gil_lock;
        override f = this->get_override("info");
        if (f)
            f();
        else
            Cimage::info();
    }
};

void translate_FileError(FileError const & e)
{
    PyErr_SetString(PyExc_OSError, "FileError");
}

BOOST_PYTHON_MODULE(pymycpp)
{
    PyEval_InitThreads();

    register_exception_translator<FileError>(&translate_FileError);

    class_<CimageWrapper, boost::noncopyable>(
            "Cimage", init<size_t, size_t>())
        .def("width", &CimageWrapper::width)
        .def("height", &CimageWrapper::height)
        .def("how_many_bytes", &CimageWrapper::how_many_bytes)
        .staticmethod("how_many_bytes")
        .def("info", &CimageWrapper::info)
        ;

    class_<Cproc, boost::noncopyable>(
            "Cproc", init<>())
        .def("run", &Cproc::run)
        .def("stop", &Cproc::stop)
        ;

    class_<Bitmap, boost::noncopyable>(
            "Bitmap", init<std::string>())
        .def("get_width", &Bitmap::get_width)
        .def("get_height", &Bitmap::get_height)
        .def("save", &Bitmap::save)
        ;
}
<commit_msg>Issue #17: using BitmapWrapper class instead of Bitmap directly for Python exposure<commit_after>#include <boost/python.hpp>
#include <boost/python/exception_translator.hpp>
#include "cimage.h"
#include "cproc.h"
#include "gil.h"
#include "except.h"
#include "bitmap.h"

using namespace boost::python;

class BitmapWrapper : public Bitmap
                      , public wrapper<Bitmap>
{
    public:
        BitmapWrapper(std::string filepath)
            : Bitmap(filepath)
        {
            // nop
        }
};

class CimageWrapper
    : public Cimage
    , public wrapper<Cimage>
{
public:
    CimageWrapper(size_t width, size_t height)
        : Cimage(width, height)
    {

    }

public:
    void info()
    {
        ScopedPythonGILLock gil_lock;
        override f = this->get_override("info");
        if (f)
            f();
        else
            Cimage::info();
    }
};

void translate_FileError(FileError const & e)
{
    PyErr_SetString(PyExc_OSError, "FileError");
}

BOOST_PYTHON_MODULE(pymycpp)
{
    PyEval_InitThreads();

    register_exception_translator<FileError>(&translate_FileError);

    class_<CimageWrapper, boost::noncopyable>(
            "Cimage", init<size_t, size_t>())
        .def("width", &CimageWrapper::width)
        .def("height", &CimageWrapper::height)
        .def("how_many_bytes", &CimageWrapper::how_many_bytes)
        .staticmethod("how_many_bytes")
        .def("info", &CimageWrapper::info)
        ;

    class_<Cproc, boost::noncopyable>(
            "Cproc", init<>())
        .def("run", &Cproc::run)
        .def("stop", &Cproc::stop)
        ;

    class_<BitmapWrapper, boost::noncopyable>(
            "Bitmap", init<std::string>())
        .def("get_width", &BitmapWrapper::get_width)
        .def("get_height", &BitmapWrapper::get_height)
        .def("save", &BitmapWrapper::save)
        ;
}
<|endoftext|>