<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>
#include "Signature.h"
#include "SignalRoutine.h"

#define POSIX_MUTEX

#include "Lock.h"

#define MAX_LOG_LEN 50000
#define MAX_THREAD_NUM 50

static bool start = false;
static pthread_t thread_idx_map[MAX_THREAD_NUM];
static int thread_idx = 1; //start from 1, make 0 be a terminal

static unsigned **GLOG = NULL;
static unsigned *GIDX = NULL;

static int num_shared_vars = 0;

//static struct timeval tpstart, tpend;

int static inline threadid(pthread_t tid) {
    for (int i = 1; i < thread_idx; i++) {
        if (thread_idx_map[i] == tid) {
            return i;
        }
    }

    return -1;
}

void static inline threadcreate(pthread_t tid) {
    thread_idx_map[thread_idx++] = tid;

    if (thread_idx > MAX_THREAD_NUM) {
        printf("Too many threads!\n");
        exit(0);
    }
}

void static inline store(int svId, int tid) {
    int currentIdx = GIDX[svId];
    if (currentIdx > 0 && (int) (GLOG[svId][currentIdx - 2]) == tid) {
        GLOG[svId][currentIdx - 1]++;
    } else {
        GLOG[svId][currentIdx] = tid;
        GLOG[svId][currentIdx + 1] = 1;
        GIDX[svId] += 2;
    }
}

extern "C" {

    void OnInit(int svsNum) {
        printf("OnInit-Record\n");
        initializeSigRoutine();

        //start = true;
        num_shared_vars = svsNum + 2; // one for fork, and the other is for synchronizations

        for (int i = 0; i < MAX_THREAD_NUM; i++) {
            thread_idx_map[i] = 0;
        }

        initialize(num_shared_vars); // initialize locks

        GLOG = new unsigned*[num_shared_vars];
        GIDX = new unsigned[num_shared_vars];
        for (int i = 0; i < num_shared_vars; i++) {
            GLOG[i] = new unsigned[MAX_LOG_LEN];
            GIDX[i] = 0;
        }

        // main thread.
        pthread_t tid = pthread_self();
        if (threadid(tid) == -1) {
            threadcreate(tid);
        }

        //gettimeofday(&tpstart, NULL);
    }

    void OnExit(int nouse) {
        start = false;

        //gettimeofday(&tpend, NULL);
        //double timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
        //timeuse /= 1000;
        //printf("processor time is %lf ms\n", timeuse);

        Sig* sig = new Sig;
        strcpy(sig->recorder, "leap");

        FILE * fout = fopen("log.replay.dat", "wb");
        printf("OnExit-Record\n");

        fwrite(sig, sizeof (Sig), 1, fout);
        fwrite(GIDX, sizeof (unsigned), num_shared_vars, fout);
        for (int i = 0; i < num_shared_vars; i++) {
            fwrite(GLOG[i], sizeof (unsigned), GIDX[i], fout);
        }
        fclose(fout);

#ifdef DEBUG
        // debug out
        FILE* fdebug = fopen("log.debug", "w+");
        for (int i = 0; i < num_shared_vars; i++) {
            fprintf(fdebug, "%d, ", GIDX[i]);
        }
        fprintf(fdebug, "\n\n");
        for (int i = 0; i < num_shared_vars; i++) {
            for (unsigned j = 0; j < GIDX[i]; j++) {
                fprintf(fdebug, "%d, ", GLOG[i][j]);
            }
            fprintf(fdebug, "\n");
        }
        fclose(fdebug);
#endif
    }

    void OnPreLoad(int svId, int debug) {
        if (!start) {
            return;
        }

        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);

        lock(svId);

#ifdef DEBUG
        printf("OnPreLoad: %d at t%d [%d]\n", svId, _tid, debug);
#endif
        store(svId, _tid);
    }

    void OnLoad(int svId, int debug) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnLoad\n");
#endif
        unlock(svId);
    }

    void OnPreStore(int svId, int debug) {
        if (!start) {
            return;
        }

        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);

        lock(svId);
#ifdef DEBUG
        printf("OnPreStore: %d at t%d [%d]\n", svId, _tid, debug);
#endif
        store(svId, _tid);
    }

    void OnStore(int svId, int debug) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnStore\n");
#endif
        unlock(svId);
    }

    void OnPreLock(int nouse) {
#ifdef DEBUG
        if (!start) {
            return;
        }
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        printf("OnPreLock[%d]\n", _tid);
#endif
    }

    void OnLock(int nouse) {
        if (!start) {
            return;
        }

        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 2, _tid);
#ifdef DEBUG
        printf("OnLock --> t%d\n", _tid);
#endif

    }

    void OnPreUnlock(int nouse) {
#ifdef DEBUG
        if (!start) {
            return;
        }
        printf("OnpreunLock\n");
#endif
    }

    void OnUnlock(int nouse) {
#ifdef DEBUG
        if (!start) {
            return;
        }
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        printf("OnunLock <-- t%d\n", _tid);
#endif
    }

    void OnPreFork(int nouse) {
        if (!start) {
            start = true;
            //return;
        }
#ifdef DEBUG
        printf("OnPreFork\n");
#endif
        forklock(num_shared_vars - 1);
    }

    void OnFork(long forked_tid_ptr) {
        if (!start) {
            return;
        }

        pthread_t ftid = *((pthread_t*) forked_tid_ptr);
        if (threadid(ftid) == -1) {
            threadcreate(ftid);
        }
#ifdef DEBUG
        printf("OnFork\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 1, _tid);
        forkunlock(num_shared_vars - 1);
    }

    void OnPreJoin(int id) {
    }

    void OnJoin(int id) {
    }

    void OnPreWait(int condId) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnPrewait\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 2, _tid);
    }

    void OnWait(int condId, long cond_ptr, long mutex_ptr) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnWait\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 2, _tid);
    }

    void OnPreNotify(int condId) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnPreNotify\n");
#endif
        lock(num_shared_vars - 2);
    }

    void OnNotify(int condId) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnNotify\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 2, _tid);
        unlock(num_shared_vars - 2);
    }
}

/* ************************************************************************
 * Signal Process
 * ************************************************************************/

void sigroutine(int dunno) {
    printSigInformation(dunno);

    OnExit(num_shared_vars);
    exit(dunno);
}
<commit_msg>modify leaprecord<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>
#include "Signature.h"
#include "SignalRoutine.h"

#define POSIX_MUTEX

#include "Lock.h"

#define MAX_LOG_LEN 50000
#define MAX_THREAD_NUM 50

static bool start = false;
static pthread_t thread_idx_map[MAX_THREAD_NUM];
static int thread_idx = 1; //start from 1, make 0 be a terminal

static unsigned **GLOG = NULL;
static unsigned *GIDX = NULL;

static int num_shared_vars = 0;

// set when log is too long
static bool stop_recording = false;

//static struct timeval tpstart, tpend;

int static inline threadid(pthread_t tid) {
    for (int i = 1; i < thread_idx; i++) {
        if (thread_idx_map[i] == tid) {
            return i;
        }
    }

    return -1;
}

void static inline threadcreate(pthread_t tid) {
    thread_idx_map[thread_idx++] = tid;

    if (thread_idx > MAX_THREAD_NUM) {
        printf("Too many threads!\n");
        exit(0);
    }
}

void static inline store(int svId, int tid) {
    if(stop_recording){
        return;
    }

    int currentIdx = GIDX[svId];
    if(currentIdx >= MAX_LOG_LEN){
	printf("Log is too long to record! Stop recording!\n");
	stop_recording = true;
	return;
    }

    if (currentIdx > 0 && (int) (GLOG[svId][currentIdx - 2]) == tid) {
        GLOG[svId][currentIdx - 1]++;
    } else {
        GLOG[svId][currentIdx] = tid;
        GLOG[svId][currentIdx + 1] = 1;
        GIDX[svId] += 2;
    }
}

extern "C" {

    void OnInit(int svsNum) {
        printf("OnInit-Record\n");
        initializeSigRoutine();

        //start = true;
        num_shared_vars = svsNum + 2; // one for fork, and the other is for synchronizations

        for (int i = 0; i < MAX_THREAD_NUM; i++) {
            thread_idx_map[i] = 0;
        }

        initialize(num_shared_vars); // initialize locks

        GLOG = new unsigned*[num_shared_vars];
        GIDX = new unsigned[num_shared_vars];
        for (int i = 0; i < num_shared_vars; i++) {
            GLOG[i] = new unsigned[MAX_LOG_LEN];
            GIDX[i] = 0;
        }

        // main thread.
        pthread_t tid = pthread_self();
        if (threadid(tid) == -1) {
            threadcreate(tid);
        }

        //gettimeofday(&tpstart, NULL);
    }

    void OnExit(int nouse) {
        start = false;

        //gettimeofday(&tpend, NULL);
        //double timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
        //timeuse /= 1000;
        //printf("processor time is %lf ms\n", timeuse);

        Sig* sig = new Sig;
        strcpy(sig->recorder, "leap");

        FILE * fout = fopen("log.replay.dat", "wb");
        printf("OnExit-Record\n");

        fwrite(sig, sizeof (Sig), 1, fout);
        fwrite(GIDX, sizeof (unsigned), num_shared_vars, fout);
        for (int i = 0; i < num_shared_vars; i++) {
            fwrite(GLOG[i], sizeof (unsigned), GIDX[i], fout);
        }
        fclose(fout);

#ifdef DEBUG
        // debug out
        FILE* fdebug = fopen("log.debug", "w+");
        for (int i = 0; i < num_shared_vars; i++) {
            fprintf(fdebug, "%d, ", GIDX[i]);
        }
        fprintf(fdebug, "\n\n");
        for (int i = 0; i < num_shared_vars; i++) {
            for (unsigned j = 0; j < GIDX[i]; j++) {
                fprintf(fdebug, "%d, ", GLOG[i][j]);
            }
            fprintf(fdebug, "\n");
        }
        fclose(fdebug);
#endif
    }

    void OnPreLoad(int svId, int debug) {
        if (!start) {
            return;
        }

        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);

        lock(svId);

#ifdef DEBUG
        printf("OnPreLoad: %d at t%d [%d]\n", svId, _tid, debug);
#endif
        store(svId, _tid);
    }

    void OnLoad(int svId, int debug) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnLoad\n");
#endif
        unlock(svId);
    }

    void OnPreStore(int svId, int debug) {
        if (!start) {
            return;
        }

        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);

        lock(svId);
#ifdef DEBUG
        printf("OnPreStore: %d at t%d [%d]\n", svId, _tid, debug);
#endif
        store(svId, _tid);
    }

    void OnStore(int svId, int debug) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnStore\n");
#endif
        unlock(svId);
    }

    void OnPreLock(int nouse) {
#ifdef DEBUG
        if (!start) {
            return;
        }
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        printf("OnPreLock[%d]\n", _tid);
#endif
    }

    void OnLock(int nouse) {
        if (!start) {
            return;
        }

        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 2, _tid);
#ifdef DEBUG
        printf("OnLock --> t%d\n", _tid);
#endif

    }

    void OnPreUnlock(int nouse) {
#ifdef DEBUG
        if (!start) {
            return;
        }
        printf("OnpreunLock\n");
#endif
    }

    void OnUnlock(int nouse) {
#ifdef DEBUG
        if (!start) {
            return;
        }
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        printf("OnunLock <-- t%d\n", _tid);
#endif
    }

    void OnPreFork(int nouse) {
        if (!start) {
            start = true;
            //return;
        }
#ifdef DEBUG
        printf("OnPreFork\n");
#endif
        forklock(num_shared_vars - 1);
    }

    void OnFork(long forked_tid_ptr) {
        if (!start) {
            return;
        }

        pthread_t ftid = *((pthread_t*) forked_tid_ptr);
        if (threadid(ftid) == -1) {
            threadcreate(ftid);
        }
#ifdef DEBUG
        printf("OnFork\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 1, _tid);
        forkunlock(num_shared_vars - 1);
    }

    void OnPreJoin(int id) {
    }

    void OnJoin(int id) {
    }

    void OnPreWait(int condId) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnPrewait\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 2, _tid);
    }

    void OnWait(int condId, long cond_ptr, long mutex_ptr) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnWait\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 2, _tid);
    }

    void OnPreNotify(int condId) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnPreNotify\n");
#endif
        lock(num_shared_vars - 2);
    }

    void OnNotify(int condId) {
        if (!start) {
            return;
        }
#ifdef DEBUG
        printf("OnNotify\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 2, _tid);
        unlock(num_shared_vars - 2);
    }
}

/* ************************************************************************
 * Signal Process
 * ************************************************************************/

void sigroutine(int dunno) {
    printSigInformation(dunno);

    OnExit(num_shared_vars);
    exit(dunno);
}
<|endoftext|>


<commit_before>/***************************************************************************
                          autoreplacepreferences.cpp  -  description
                             -------------------
    begin                : 20030426
    copyright            : (C) 2003 by Roberto Pariset
    email                : victorheremita@fastwebnet.it
 ***************************************************************************/

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

#include <qlayout.h>
#include <qpushbutton.h>
#include <qgroupbox.h>
#include <qlistview.h>

#include <klocale.h>
#include <klineedit.h>
#include <kglobal.h>
#include <kgenericfactory.h>
#include <kautoconfig.h>

#include "autoreplaceprefs.h"
#include "autoreplacepreferences.h"
#include "autoreplaceconfig.h"

typedef KGenericFactory<AutoReplacePreferences> AutoReplacePreferencesFactory;

K_EXPORT_COMPONENT_FACTORY( kcm_kopete_autoreplace, AutoReplacePreferencesFactory( "kcm_kopete_autoreplace" ) )

AutoReplacePreferences::AutoReplacePreferences( QWidget *parent, const char * /* name */, const QStringList &args )
: KCAutoConfigModule( AutoReplacePreferencesFactory::instance(), parent, args )
{
	( new QVBoxLayout( this ) )->setAutoAdd( true );
	preferencesDialog = new AutoReplacePrefsUI( this );

	// creates table columns (avoids new columns every time)
	preferencesDialog->m_list->addColumn( i18n("Text") );
	preferencesDialog->m_list->addColumn( i18n("Replacement") );

	// connect SIGNALS/SLOTS
	connect( preferencesDialog->m_add, SIGNAL(pressed()),
		SLOT( slotAddCouple()) );
	connect( preferencesDialog->m_remove, SIGNAL(pressed()),
		SLOT(slotRemoveCouple()) );
	/* connect( preferencesDialog->m_list, SIGNAL(selectionChanged()),
		SLOT(slotEnableRemove()) );
	connect( preferencesDialog->m_value, SIGNAL(textChanged ( const QString & )),
		SLOT( slotEnableAdd()) ); */

	m_wordListChanged=false;

	setMainWidget( preferencesDialog->gb_options , "AutoReplace Plugin" );

	m_config = new AutoReplaceConfig;
	load();
}

AutoReplacePreferences::~AutoReplacePreferences()
{
	delete m_config;
}

// reload configuration reading it from kopeterc
void AutoReplacePreferences::load()
{
	m_config->load();

	// Removes and deletes all the items in this list view and triggers an update
	preferencesDialog->m_list->clear();

	// show keys/values on gui
	AutoReplaceConfig::WordsToReplace::Iterator it;
	AutoReplaceConfig::WordsToReplace map = m_config->map();
	for ( it = map.begin(); it != map.end(); ++it )
	{
		// notice: insertItem is called automatically by the constructor
		new QListViewItem( preferencesDialog->m_list, it.key(), it.data() );
	}

	m_wordListChanged=false;
	KCAutoConfigModule::load();
}

// save list to kopeterc and creates map out of it
void AutoReplacePreferences::save()
{
	// make a list reading all values from gui
	AutoReplaceConfig::WordsToReplace newWords;
	for ( QListViewItem * i = preferencesDialog->m_list->firstChild(); i != 0; i = i->nextSibling() )
		newWords[ i->text( 0 ) ] = i->text( 1 );

	// save the words list
	m_config->setMap( newWords );
	m_config->save();

	m_wordListChanged=false;
	KCAutoConfigModule::save();
}

// read m_key m_value, create a QListViewItem
void AutoReplacePreferences::slotAddCouple()
{
	QString k = preferencesDialog->m_key->text();
	QString v = preferencesDialog->m_value->text();
	if( !k.isEmpty() && !k.isNull() && !v.isEmpty() && !v.isNull() ) {
		QListViewItem * lvi =
			new QListViewItem( preferencesDialog->m_list, k, v );
		// clear k and v [only if added]
		preferencesDialog->m_key->clear();
		preferencesDialog->m_value->clear();
		// Triggers a size, geometry and content update
		// during the next iteration of the event loop
		preferencesDialog->m_list->triggerUpdate();
		// select last added
		preferencesDialog->m_list->setSelected(lvi, true);
	}

	m_wordListChanged=true;
	slotWidgetModified();
}

// Returns a pointer to the selected item if the list view is in
// Single selection mode and an item is selected
void AutoReplacePreferences::slotRemoveCouple()
{
	QListViewItem * lvi = preferencesDialog->m_list->selectedItem();
	if( lvi )
		delete lvi;

	m_wordListChanged=true;
	slotWidgetModified();
}

/*
void AutoReplacePreferences::slotEnableAdd()
{
	//preferencesDialog->m_add
}

void AutoReplacePreferences::slotEnableRemove()
{
	preferencesDialog->m_remove->setEnabled( true );
}
*/

void AutoReplacePreferences::slotWidgetModified()
{
	setChanged( m_wordListChanged || autoConfig()->hasChanged() ) ;
}

#include "autoreplacepreferences.moc"

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>CVS_SILENT fix coding style again.<commit_after>/***************************************************************************
                          autoreplacepreferences.cpp  -  description
                             -------------------
    begin                : 20030426
    copyright            : (C) 2003 by Roberto Pariset
    email                : victorheremita@fastwebnet.it
 ***************************************************************************/

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

#include <qlayout.h>
#include <qpushbutton.h>
#include <qgroupbox.h>
#include <qlistview.h>

#include <klocale.h>
#include <klineedit.h>
#include <kglobal.h>
#include <kgenericfactory.h>
#include <kautoconfig.h>

#include "autoreplaceprefs.h"
#include "autoreplacepreferences.h"
#include "autoreplaceconfig.h"

typedef KGenericFactory<AutoReplacePreferences> AutoReplacePreferencesFactory;

K_EXPORT_COMPONENT_FACTORY( kcm_kopete_autoreplace, AutoReplacePreferencesFactory( "kcm_kopete_autoreplace" ) )

AutoReplacePreferences::AutoReplacePreferences( QWidget *parent, const char * /* name */, const QStringList &args )
: KCAutoConfigModule( AutoReplacePreferencesFactory::instance(), parent, args )
{
	( new QVBoxLayout( this ) )->setAutoAdd( true );
	preferencesDialog = new AutoReplacePrefsUI( this );

	// creates table columns (avoids new columns every time)
	preferencesDialog->m_list->addColumn( i18n("Text" ) );
	preferencesDialog->m_list->addColumn( i18n("Replacement" ) );

	// connect SIGNALS/SLOTS
	connect( preferencesDialog->m_add, SIGNAL(pressed()),
		SLOT( slotAddCouple()) );
	connect( preferencesDialog->m_remove, SIGNAL(pressed()),
		SLOT(slotRemoveCouple()) );
	/* connect( preferencesDialog->m_list, SIGNAL(selectionChanged()),
		SLOT(slotEnableRemove()) );
	connect( preferencesDialog->m_value, SIGNAL(textChanged ( const QString & )),
		SLOT( slotEnableAdd()) ); */

	m_wordListChanged = false;

	setMainWidget( preferencesDialog->gb_options, "AutoReplace Plugin" );

	m_config = new AutoReplaceConfig;
	load();
}

AutoReplacePreferences::~AutoReplacePreferences()
{
	delete m_config;
}

// reload configuration reading it from kopeterc
void AutoReplacePreferences::load()
{
	m_config->load();

	// Removes and deletes all the items in this list view and triggers an update
	preferencesDialog->m_list->clear();

	// show keys/values on gui
	AutoReplaceConfig::WordsToReplace::Iterator it;
	AutoReplaceConfig::WordsToReplace map = m_config->map();
	for ( it = map.begin(); it != map.end(); ++it )
	{
		// notice: insertItem is called automatically by the constructor
		new QListViewItem( preferencesDialog->m_list, it.key(), it.data() );
	}

	m_wordListChanged = false;
	KCAutoConfigModule::load();
}

// save list to kopeterc and creates map out of it
void AutoReplacePreferences::save()
{
	// make a list reading all values from gui
	AutoReplaceConfig::WordsToReplace newWords;
	for ( QListViewItem * i = preferencesDialog->m_list->firstChild(); i != 0; i = i->nextSibling() )
		newWords[ i->text( 0 ) ] = i->text( 1 );

	// save the words list
	m_config->setMap( newWords );
	m_config->save();

	m_wordListChanged = false;
	KCAutoConfigModule::save();
}

// read m_key m_value, create a QListViewItem
void AutoReplacePreferences::slotAddCouple()
{
	QString k = preferencesDialog->m_key->text();
	QString v = preferencesDialog->m_value->text();
	if ( !k.isEmpty() && !k.isNull() && !v.isEmpty() && !v.isNull() )
	{
		QListViewItem * lvi = new QListViewItem( preferencesDialog->m_list, k, v );
		// clear k and v [only if added]
		preferencesDialog->m_key->clear();
		preferencesDialog->m_value->clear();
		// Triggers a size, geometry and content update
		// during the next iteration of the event loop
		preferencesDialog->m_list->triggerUpdate();
		// select last added
		preferencesDialog->m_list->setSelected( lvi, true );
	}

	m_wordListChanged = true;
	slotWidgetModified();
}

// Returns a pointer to the selected item if the list view is in
// Single selection mode and an item is selected
void AutoReplacePreferences::slotRemoveCouple()
{
	QListViewItem *lvi = preferencesDialog->m_list->selectedItem();
	if ( lvi )
		delete lvi;

	m_wordListChanged = true;
	slotWidgetModified();
}

/*
void AutoReplacePreferences::slotEnableAdd()
{
	//preferencesDialog->m_add
}

void AutoReplacePreferences::slotEnableRemove()
{
	preferencesDialog->m_remove->setEnabled( true );
}
*/

void AutoReplacePreferences::slotWidgetModified()
{
	setChanged( m_wordListChanged || autoConfig()->hasChanged() );
}

#include "autoreplacepreferences.moc"

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>#include "CmdSession.h"

#ifdef ARGP_FOUND

#include <string>
#include <memory>
#include <cstdlib>

#include <SmurffCpp/Version.h>
#include <SmurffCpp/Configs/Config.h>
#include <SmurffCpp/Configs/NoiseConfig.h>

// !!! DO NOT CHANGE ORDER OF INCLUDES (<algorithm>, <argp.h>)!!!
// https://stackoverflow.com/questions/19043109/gcc-4-8-1-combining-c-code-with-c11-code
#include <SmurffCpp/IO/GenericIO.h>
#include <SmurffCpp/IO/MatrixIO.h>
#include <argp.h>

#include <argp.h>

using namespace Eigen;

using namespace smurff;
using namespace generic_io;
using namespace matrix_io;

enum OPT_ENUM
{
   ROW_PRIOR = 1024, COL_PRIOR, ROW_FEATURES, COL_FEATURES, FNAME_ROW_MODEL, FNAME_COL_MODEL, FNAME_TEST, FNAME_TRAIN,
   BURNIN, NSAMPLES, NUM_LATENT, PRECISION, ADAPTIVE, LAMBDA_BETA, TOL, DIRECT,
   RESTORE_PREFIX, RESTORE_SUFFIX, SAVE_PREFIX, SAVE_SUFFIX, SAVE_FREQ, THRESHOLD, VERBOSE, QUIET, VERSION, SEED,
   INIT_MODEL, CENTER, STATUS_FILE
};

void set_noise_model(Config& config, std::string noiseName, std::string optarg)
{
   NoiseConfig nc;
   nc.setNoiseType(smurff::stringToNoiseType(noiseName));
   if (nc.getNoiseType() == NoiseTypes::adaptive)
   {
      char *token, *str = strdup(optarg.c_str());

      if(str && (token = strsep(&str, ",")))
         nc.sn_init = strtod(token, NULL);

      if(str && (token = strsep(&str, ",")))
         nc.sn_max = strtod(token, NULL);
   }
   else if (nc.getNoiseType() == NoiseTypes::fixed)
   {
      nc.precision = strtod(optarg.c_str(), NULL);
   }

   if(!config.m_train)
   {
      THROWERROR("train data is not provided");
   }

   // set global noise model
   if (config.m_train->getNoiseConfig().getNoiseType() == NoiseTypes::unset)
   config.m_train->setNoiseConfig(nc);

   //set for row/col feautres
   for(auto m: config.m_row_features)
      if (m->getNoiseConfig().getNoiseType() == NoiseTypes::unset)
         m->setNoiseConfig(nc);

   for(auto m: config.m_col_features)
      if (m->getNoiseConfig().getNoiseType() == NoiseTypes::unset)
         m->setNoiseConfig(nc);
}

static int parse_opts(int key, char *optarg, struct argp_state *state)
{
   Config &c = *(Config *)(state->input);

   switch (key)
   {
      case ROW_PRIOR:       c.row_prior_type          = stringToPriorType(optarg); break;
      case COL_PRIOR:       c.col_prior_type          = stringToPriorType(optarg); break;

      case ROW_FEATURES:    c.m_row_features.push_back(read_matrix(optarg, false)); break;
      case COL_FEATURES:    c.m_col_features.push_back(read_matrix(optarg, false)); break;

      case CENTER:          break;

      case FNAME_TRAIN:     c.m_train              = read_data_config(optarg, true); break;
      case LAMBDA_BETA:     c.lambda_beta        = strtod(optarg, NULL); break;
      case BURNIN:          c.burnin             = strtol(optarg, NULL, 10); break;
      case TOL:             c.tol                = atof(optarg); break;
      case DIRECT:          c.direct             = true; break;
      case FNAME_TEST:      c.m_test               = read_data_config(optarg, true); break;
      case NUM_LATENT:      c.num_latent         = strtol(optarg, NULL, 10); break;
      case NSAMPLES:        c.nsamples           = strtol(optarg, NULL, 10); break;
      case SEED:            c.random_seed_set = true;
                            c.random_seed = strtol(optarg, NULL, 10);
                            break;
      case RESTORE_PREFIX:  c.restore_prefix      = std::string(optarg); break;
      case RESTORE_SUFFIX:  c.restore_suffix      = std::string(optarg); break;
      case SAVE_PREFIX:     c.setSavePrefix(std::string(optarg)); break;
      case SAVE_SUFFIX:     c.save_suffix      = std::string(optarg); break;
      case SAVE_FREQ:       c.save_freq        = strtol(optarg, NULL, 10); break;

      case PRECISION:       set_noise_model(c, NOISE_NAME_FIXED, optarg); break;
      case ADAPTIVE:        set_noise_model(c, NOISE_NAME_ADAPTIVE, optarg); break;

      case THRESHOLD:       c.threshold          = strtod(optarg, 0); c.classify = true; break;
      case INIT_MODEL:      c.model_init_type = stringToModelInitType(optarg); break;
      case VERBOSE:         c.verbose            = optarg ? strtol(optarg, NULL, 0) : 1; break;
      case QUIET:           c.verbose            = 0; break;
      case VERSION:         std::cout <<  "SMURFF " << smurff::SMURFF_VERSION << std::endl; exit(0);
      case STATUS_FILE:     c.csv_status         = optarg; break;
      default:              return ARGP_ERR_UNKNOWN;
   }

    return 0;
}

void CmdSession::setFromArgs(int argc, char** argv)
{
    // Program documentation.
    char doc[] = "SMURFF: Scalable Matrix Factorization Framework\n\thttp://github.com/ExaScience/smurff";

    struct argp_option options[] =
    {
        {0,0,0,0,"Priors and side Info:",1},
        {"row-prior",	     ROW_PRIOR     , "PRIOR", 0, "One of <normal|normalone||spikeandslab|macau|macauone>"},
        {"col-prior",	     COL_PRIOR	, "PRIOR", 0, "One of <normal|normalone|spikeandslab|macau|macauone>"},
        {"row-features",     ROW_FEATURES	, "FILE",  0, "side info for rows"},
        {"col-features",     COL_FEATURES	, "FILE",  0, "side info for cols"},
        {"row-model",        FNAME_ROW_MODEL	, "FILE",  0, "initialization matrix for row model"},
        {"col-model",        FNAME_COL_MODEL	, "FILE",  0, "initialization matrix for col model"},
        {"center",           CENTER	        , "MODE",  0, "center <global|rows|cols|none>"},
        {0,0,0,0,"Test and train matrices:",2},
        {"test",	     FNAME_TEST    , "FILE",  0, "test data (for computing RMSE)"},
        {"train",	     FNAME_TRAIN   , "FILE",  0, "train data file"},
        {0,0,0,0,"General parameters:",3},
        {"burnin",	     BURNIN	, "NUM",   0, "200  number of samples to discard"},
        {"nsamples",	     NSAMPLES	, "NUM",   0, "800  number of samples to collect"},
        {"num-latent",	     NUM_LATENT	, "NUM",   0, "96  number of latent dimensions"},
        {"restore-prefix",   RESTORE_PREFIX	, "PATH",   0, "prefix for file to initialize state"},
        {"restore-suffix",   RESTORE_SUFFIX	, "EXT",   0, "suffix for initialization files (.csv or .ddm)"},
        {"init-model",       INIT_MODEL	, "NAME",   0, "One of <random|zero>"},
        {"save-prefix",      SAVE_PREFIX	, "PATH",   0, "prefix for result files"},
        {"save-suffix",      SAVE_SUFFIX	, "EXT",   0, "suffix for result files (.csv or .ddm)"},
        {"save-freq",        SAVE_FREQ	, "NUM",   0, "save every n iterations (0 == never, -1 == final model)"},
        {"threshold",        THRESHOLD	, "NUM",   0, "threshold for binary classification"},
        {"verbose",          VERBOSE	, "NUM",   OPTION_ARG_OPTIONAL, "verbose output (default = 1)"},
        {"quiet",            QUIET	, 0,   0, "no output"},
        {"version",          VERSION    , 0,   0, "print version info"},
        {"status",           STATUS_FILE, "FILE",  0, "output progress to csv file"},
        {"seed",             SEED, "NUM",  0, "random number generator seed"},
        {0,0,0,0,"Noise model:",4},
        {"precision",	     PRECISION	, "NUM",   0, "5.0  precision of observations"},
        {"adaptive",	     ADAPTIVE	, "NUM,NUM",   0, "1.0,10.0  adaptive precision of observations"},
        {0,0,0,0,"For the macau prior:",5},
        {"lambda-beta",	     LAMBDA_BETA	, "NUM",   0, "10.0  initial value of lambda beta"},
        {"tol",              TOL        , "NUM",   0, "1e-6  tolerance for CG"},
        {"direct",           DIRECT     , 0,   0, "false Use Cholesky decomposition i.o. CG Solver"},
        {0,0,0,0,"General Options:",0},
        {0}
    };

    Config cfg;
    struct argp argp = { options, parse_opts, 0, doc };
    if(argp_parse (&argp, argc, argv, 0, 0, &cfg) != 0)
    {
      THROWERROR("Failed to parse command line arguments");
    }

    setFromConfig(cfg);
}

#endif
<commit_msg>--probit command line option<commit_after>#include "CmdSession.h"

#ifdef ARGP_FOUND

#include <string>
#include <memory>
#include <cstdlib>

#include <SmurffCpp/Version.h>
#include <SmurffCpp/Configs/Config.h>
#include <SmurffCpp/Configs/NoiseConfig.h>

// !!! DO NOT CHANGE ORDER OF INCLUDES (<algorithm>, <argp.h>)!!!
// https://stackoverflow.com/questions/19043109/gcc-4-8-1-combining-c-code-with-c11-code
#include <SmurffCpp/IO/GenericIO.h>
#include <SmurffCpp/IO/MatrixIO.h>
#include <argp.h>

#include <argp.h>

using namespace Eigen;

using namespace smurff;
using namespace generic_io;
using namespace matrix_io;

enum OPT_ENUM
{
   ROW_PRIOR = 1024, COL_PRIOR, ROW_FEATURES, COL_FEATURES, FNAME_ROW_MODEL, FNAME_COL_MODEL, FNAME_TEST, FNAME_TRAIN,
   BURNIN, NSAMPLES, NUM_LATENT, PRECISION, ADAPTIVE, PROBIT, LAMBDA_BETA, TOL, DIRECT,
   RESTORE_PREFIX, RESTORE_SUFFIX, SAVE_PREFIX, SAVE_SUFFIX, SAVE_FREQ, THRESHOLD, VERBOSE, QUIET, VERSION, SEED,
   INIT_MODEL, CENTER, STATUS_FILE
};

void set_noise_model(Config& config, std::string noiseName, std::string optarg)
{
   NoiseConfig nc;
   nc.setNoiseType(smurff::stringToNoiseType(noiseName));
   if (nc.getNoiseType() == NoiseTypes::adaptive)
   {
      char *token, *str = strdup(optarg.c_str());

      if(str && (token = strsep(&str, ",")))
         nc.sn_init = strtod(token, NULL);

      if(str && (token = strsep(&str, ",")))
         nc.sn_max = strtod(token, NULL);
   }
   else if (nc.getNoiseType() == NoiseTypes::fixed)
   {
      nc.precision = strtod(optarg.c_str(), NULL);
   }
   else if (nc.getNoiseType() == NoiseTypes::probit)
   {
      nc.threshold = strtod(optarg.c_str(), NULL);
   }

   if(!config.m_train)
   {
      THROWERROR("train data is not provided");
   }

   // set global noise model
   if (config.m_train->getNoiseConfig().getNoiseType() == NoiseTypes::unset)
   config.m_train->setNoiseConfig(nc);

   //set for row/col feautres
   for(auto m: config.m_row_features)
      if (m->getNoiseConfig().getNoiseType() == NoiseTypes::unset)
         m->setNoiseConfig(nc);

   for(auto m: config.m_col_features)
      if (m->getNoiseConfig().getNoiseType() == NoiseTypes::unset)
         m->setNoiseConfig(nc);
}

static int parse_opts(int key, char *optarg, struct argp_state *state)
{
   Config &c = *(Config *)(state->input);

   switch (key)
   {
      case ROW_PRIOR:       c.row_prior_type          = stringToPriorType(optarg); break;
      case COL_PRIOR:       c.col_prior_type          = stringToPriorType(optarg); break;

      case ROW_FEATURES:    c.m_row_features.push_back(read_matrix(optarg, false)); break;
      case COL_FEATURES:    c.m_col_features.push_back(read_matrix(optarg, false)); break;

      case CENTER:          break;

      case FNAME_TRAIN:     c.m_train              = read_data_config(optarg, true); break;
      case LAMBDA_BETA:     c.lambda_beta        = strtod(optarg, NULL); break;
      case BURNIN:          c.burnin             = strtol(optarg, NULL, 10); break;
      case TOL:             c.tol                = atof(optarg); break;
      case DIRECT:          c.direct             = true; break;
      case FNAME_TEST:      c.m_test               = read_data_config(optarg, true); break;
      case NUM_LATENT:      c.num_latent         = strtol(optarg, NULL, 10); break;
      case NSAMPLES:        c.nsamples           = strtol(optarg, NULL, 10); break;
      case SEED:            c.random_seed_set = true;
                            c.random_seed = strtol(optarg, NULL, 10);
                            break;
      case RESTORE_PREFIX:  c.restore_prefix      = std::string(optarg); break;
      case RESTORE_SUFFIX:  c.restore_suffix      = std::string(optarg); break;
      case SAVE_PREFIX:     c.setSavePrefix(std::string(optarg)); break;
      case SAVE_SUFFIX:     c.save_suffix      = std::string(optarg); break;
      case SAVE_FREQ:       c.save_freq        = strtol(optarg, NULL, 10); break;

      case PRECISION:       set_noise_model(c, NOISE_NAME_FIXED, optarg); break;
      case ADAPTIVE:        set_noise_model(c, NOISE_NAME_ADAPTIVE, optarg); break;
      case PROBIT:          set_noise_model(c, NOISE_NAME_PROBIT, optarg); break;

      case THRESHOLD:       c.threshold          = strtod(optarg, 0); c.classify = true; break;
      case INIT_MODEL:      c.model_init_type = stringToModelInitType(optarg); break;
      case VERBOSE:         c.verbose            = optarg ? strtol(optarg, NULL, 0) : 1; break;
      case QUIET:           c.verbose            = 0; break;
      case VERSION:         std::cout <<  "SMURFF " << smurff::SMURFF_VERSION << std::endl; exit(0);
      case STATUS_FILE:     c.csv_status         = optarg; break;
      default:              return ARGP_ERR_UNKNOWN;
   }

    return 0;
}

void CmdSession::setFromArgs(int argc, char** argv)
{
    // Program documentation.
    char doc[] = "SMURFF: Scalable Matrix Factorization Framework\n\thttp://github.com/ExaScience/smurff";

    struct argp_option options[] =
    {
        {0,0,0,0,"Priors and side Info:",1},
        {"row-prior",	     ROW_PRIOR     , "PRIOR", 0, "One of <normal|normalone||spikeandslab|macau|macauone>"},
        {"col-prior",	     COL_PRIOR	, "PRIOR", 0, "One of <normal|normalone|spikeandslab|macau|macauone>"},
        {"row-features",     ROW_FEATURES	, "FILE",  0, "side info for rows"},
        {"col-features",     COL_FEATURES	, "FILE",  0, "side info for cols"},
        {"row-model",        FNAME_ROW_MODEL	, "FILE",  0, "initialization matrix for row model"},
        {"col-model",        FNAME_COL_MODEL	, "FILE",  0, "initialization matrix for col model"},
        {"center",           CENTER	        , "MODE",  0, "center <global|rows|cols|none>"},
        {0,0,0,0,"Test and train matrices:",2},
        {"test",	     FNAME_TEST    , "FILE",  0, "test data (for computing RMSE)"},
        {"train",	     FNAME_TRAIN   , "FILE",  0, "train data file"},
        {0,0,0,0,"General parameters:",3},
        {"burnin",	     BURNIN	, "NUM",   0, "200  number of samples to discard"},
        {"nsamples",	     NSAMPLES	, "NUM",   0, "800  number of samples to collect"},
        {"num-latent",	     NUM_LATENT	, "NUM",   0, "96  number of latent dimensions"},
        {"restore-prefix",   RESTORE_PREFIX	, "PATH",   0, "prefix for file to initialize state"},
        {"restore-suffix",   RESTORE_SUFFIX	, "EXT",   0, "suffix for initialization files (.csv or .ddm)"},
        {"init-model",       INIT_MODEL	, "NAME",   0, "One of <random|zero>"},
        {"save-prefix",      SAVE_PREFIX	, "PATH",   0, "prefix for result files"},
        {"save-suffix",      SAVE_SUFFIX	, "EXT",   0, "suffix for result files (.csv or .ddm)"},
        {"save-freq",        SAVE_FREQ	, "NUM",   0, "save every n iterations (0 == never, -1 == final model)"},
        {"threshold",        THRESHOLD	, "NUM",   0, "threshold for binary classification"},
        {"verbose",          VERBOSE	, "NUM",   OPTION_ARG_OPTIONAL, "verbose output (default = 1)"},
        {"quiet",            QUIET	, 0,   0, "no output"},
        {"version",          VERSION    , 0,   0, "print version info"},
        {"status",           STATUS_FILE, "FILE",  0, "output progress to csv file"},
        {"seed",             SEED, "NUM",  0, "random number generator seed"},
        {0,0,0,0,"Noise model:",4},
        {"precision",	     PRECISION	, "NUM",   0, "5.0  precision of observations"},
        {"adaptive",	     ADAPTIVE	, "NUM,NUM",   0, "1.0,10.0  adaptive precision of observations"},
        {"probit",	     PROBIT	, "THRESHOLD",   0, "0.0  probit noise model with given threshold"},
        {0,0,0,0,"For the macau prior:",5},
        {"lambda-beta",	     LAMBDA_BETA	, "NUM",   0, "10.0  initial value of lambda beta"},
        {"tol",              TOL        , "NUM",   0, "1e-6  tolerance for CG"},
        {"direct",           DIRECT     , 0,   0, "false Use Cholesky decomposition i.o. CG Solver"},
        {0,0,0,0,"General Options:",0},
        {0}
    };

    Config cfg;
    struct argp argp = { options, parse_opts, 0, doc };
    if(argp_parse (&argp, argc, argv, 0, 0, &cfg) != 0)
    {
      THROWERROR("Failed to parse command line arguments");
    }

    setFromConfig(cfg);
}

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "topojson_datasource.hpp"
#include "topojson_featureset.hpp"

#include <fstream>
#include <algorithm>

// boost
#include <boost/algorithm/string.hpp>

// mapnik
#include <mapnik/unicode.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/geometry_adapters.hpp>
#include <mapnik/json/topojson_grammar.hpp>
#include <mapnik/json/topojson_utils.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/util/file_io.hpp>
#include <mapnik/make_unique.hpp>

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(topojson_datasource)

struct attr_value_converter
{
    mapnik::eAttributeType operator() (mapnik::value_integer /*val*/) const
    {
        return mapnik::Integer;
    }

    mapnik::eAttributeType operator() (double /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (float /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (bool /*val*/) const
    {
        return mapnik::Boolean;
    }

    mapnik::eAttributeType operator() (std::string const& /*val*/) const
    {
        return mapnik::String;
    }

    mapnik::eAttributeType operator() (mapnik::value_unicode_string const& /*val*/) const
    {
        return mapnik::String;
    }

    mapnik::eAttributeType operator() (mapnik::value_null const& /*val*/) const
    {
        return mapnik::String;
    }
};

struct geometry_type_visitor
{
    int operator() (mapnik::topojson::point const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Point);
    }
    int operator() (mapnik::topojson::multi_point const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Point);
    }
    int operator() (mapnik::topojson::linestring const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::LineString);
    }
    int operator() (mapnik::topojson::multi_linestring const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::LineString);
    }
    int operator() (mapnik::topojson::polygon const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Polygon);
    }
    int operator() (mapnik::topojson::multi_polygon const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Polygon);
    }
    int operator() (mapnik::topojson::invalid const&) const
    {
        return -1;
    }
};

struct collect_attributes_visitor
{
    mapnik::layer_descriptor & desc_;
    collect_attributes_visitor(mapnik::layer_descriptor & desc):
      desc_(desc) {}

    void operator() (mapnik::topojson::invalid const&) {}

    template <typename GeomType>
    void operator() (GeomType const& g)
    {
        if (g.props)
        {
            for (auto const& p : *g.props)
            {
                desc_.add_descriptor(mapnik::attribute_descriptor(std::get<0>(p),
                                                                  mapnik::util::apply_visitor(attr_value_converter(),
                                                                                std::get<1>(p))));
            }
        }
    }
};

topojson_datasource::topojson_datasource(parameters const& params)
  : datasource(params),
    type_(datasource::Vector),
    desc_(topojson_datasource::name(),
          *params.get<std::string>("encoding","utf-8")),
    filename_(),
    inline_string_(),
    extent_(),
    tr_(new mapnik::transcoder(*params.get<std::string>("encoding","utf-8"))),
    tree_(nullptr)
{
    boost::optional<std::string> inline_string = params.get<std::string>("inline");
    if (inline_string)
    {
        inline_string_ = *inline_string;
    }
    else
    {
        boost::optional<std::string> file = params.get<std::string>("file");
        if (!file) throw mapnik::datasource_exception("TopoJSON Plugin: missing <file> parameter");

        boost::optional<std::string> base = params.get<std::string>("base");
        if (base)
            filename_ = *base + "/" + *file;
        else
            filename_ = *file;
    }
    if (!inline_string_.empty())
    {
        parse_topojson(inline_string_);
    }
    else
    {
        mapnik::util::file file(filename_);
        if (!file.open())
        {
            throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + filename_ + "'");
        }
        std::string file_buffer;
        file_buffer.resize(file.size());
        std::fread(&file_buffer[0], file.size(), 1, file.get());
        parse_topojson(file_buffer);
    }
}

namespace {
using base_iterator_type = std::string::const_iterator;
const mapnik::topojson::topojson_grammar<base_iterator_type> g;
}

template <typename T>
void topojson_datasource::parse_topojson(T const& buffer)
{
    boost::spirit::standard::space_type space;
    bool result = boost::spirit::qi::phrase_parse(buffer.begin(), buffer.end(), g, space, topo_);
    if (!result)
    {
        throw mapnik::datasource_exception("topojson_datasource: Failed parse TopoJSON file '" + filename_ + "'");
    }

    using values_container = std::vector< std::pair<box_type, std::size_t> >;
    values_container values;
    values.reserve(topo_.geometries.size());

    std::size_t geometry_index = 0;

    for (auto const& geom : topo_.geometries)
    {
        mapnik::box2d<double> box = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo_), geom);
        if (box.valid())
        {
            if (geometry_index == 0)
            {
                extent_ = box;
                collect_attributes_visitor assessor(desc_);
                mapnik::util::apply_visitor( std::ref(assessor), geom);
            }
            else
            {
                extent_.expand_to_include(box);
            }
            values.emplace_back(box, geometry_index);
            ++geometry_index;
        }
    }

    // packing algorithm
    tree_ = std::make_unique<spatial_index_type>(values);
}

topojson_datasource::~topojson_datasource() { }

const char * topojson_datasource::name()
{
    return "topojson";
}

boost::optional<mapnik::datasource_geometry_t> topojson_datasource::get_geometry_type() const
{
    boost::optional<mapnik::datasource_geometry_t> result;
    int multi_type = 0;
    std::size_t num_features = topo_.geometries.size();
    for (std::size_t i = 0; i < num_features && i < 5; ++i)
    {
        mapnik::topojson::geometry const& geom = topo_.geometries[i];
        int type = mapnik::util::apply_visitor(geometry_type_visitor(),geom);
        if (type > 0)
        {
            if (multi_type > 0 && multi_type != type)
            {
                result.reset(mapnik::datasource_geometry_t::Collection);
                return result;
            }
            else
            {
                result.reset(static_cast<mapnik::datasource_geometry_t>(type));
            }
            multi_type = type;
        }
    }
    return result;
}

mapnik::datasource::datasource_t topojson_datasource::type() const
{
    return type_;
}

mapnik::box2d<double> topojson_datasource::envelope() const
{
    return extent_;
}

mapnik::layer_descriptor topojson_datasource::get_descriptor() const
{
    return desc_;
}

mapnik::featureset_ptr topojson_datasource::features(mapnik::query const& q) const
{
    // if the query box intersects our world extent then query for features
    mapnik::box2d<double> const& box = q.get_bbox();
    if (extent_.intersects(box))
    {
        topojson_featureset::array_type index_array;
        if (tree_)
        {
            tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array));
            return std::make_shared<topojson_featureset>(topo_, *tr_, std::move(index_array));
        }
    }
    // otherwise return an empty featureset pointer
    return mapnik::featureset_ptr();
}

mapnik::featureset_ptr topojson_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
    mapnik::box2d<double> query_bbox(pt, pt);
    query_bbox.pad(tol);
    mapnik::query q(query_bbox);
    for (auto const& attr_info : desc_.get_descriptors())
    {
        q.add_property_name(attr_info.get_name());
    }
    return features(q);
}
<commit_msg>topojson : fix geometry index logic<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "topojson_datasource.hpp"
#include "topojson_featureset.hpp"

#include <fstream>
#include <algorithm>

// boost
#include <boost/algorithm/string.hpp>

// mapnik
#include <mapnik/unicode.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/geometry_adapters.hpp>
#include <mapnik/json/topojson_grammar.hpp>
#include <mapnik/json/topojson_utils.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/util/file_io.hpp>
#include <mapnik/make_unique.hpp>

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(topojson_datasource)

struct attr_value_converter
{
    mapnik::eAttributeType operator() (mapnik::value_integer /*val*/) const
    {
        return mapnik::Integer;
    }

    mapnik::eAttributeType operator() (double /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (float /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (bool /*val*/) const
    {
        return mapnik::Boolean;
    }

    mapnik::eAttributeType operator() (std::string const& /*val*/) const
    {
        return mapnik::String;
    }

    mapnik::eAttributeType operator() (mapnik::value_unicode_string const& /*val*/) const
    {
        return mapnik::String;
    }

    mapnik::eAttributeType operator() (mapnik::value_null const& /*val*/) const
    {
        return mapnik::String;
    }
};

struct geometry_type_visitor
{
    int operator() (mapnik::topojson::point const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Point);
    }
    int operator() (mapnik::topojson::multi_point const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Point);
    }
    int operator() (mapnik::topojson::linestring const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::LineString);
    }
    int operator() (mapnik::topojson::multi_linestring const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::LineString);
    }
    int operator() (mapnik::topojson::polygon const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Polygon);
    }
    int operator() (mapnik::topojson::multi_polygon const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Polygon);
    }
    int operator() (mapnik::topojson::invalid const&) const
    {
        return -1;
    }
};

struct collect_attributes_visitor
{
    mapnik::layer_descriptor & desc_;
    collect_attributes_visitor(mapnik::layer_descriptor & desc):
      desc_(desc) {}

    void operator() (mapnik::topojson::invalid const&) {}

    template <typename GeomType>
    void operator() (GeomType const& g)
    {
        if (g.props)
        {
            for (auto const& p : *g.props)
            {
                desc_.add_descriptor(mapnik::attribute_descriptor(std::get<0>(p),
                                                                  mapnik::util::apply_visitor(attr_value_converter(),
                                                                                std::get<1>(p))));
            }
        }
    }
};

topojson_datasource::topojson_datasource(parameters const& params)
  : datasource(params),
    type_(datasource::Vector),
    desc_(topojson_datasource::name(),
          *params.get<std::string>("encoding","utf-8")),
    filename_(),
    inline_string_(),
    extent_(),
    tr_(new mapnik::transcoder(*params.get<std::string>("encoding","utf-8"))),
    tree_(nullptr)
{
    boost::optional<std::string> inline_string = params.get<std::string>("inline");
    if (inline_string)
    {
        inline_string_ = *inline_string;
    }
    else
    {
        boost::optional<std::string> file = params.get<std::string>("file");
        if (!file) throw mapnik::datasource_exception("TopoJSON Plugin: missing <file> parameter");

        boost::optional<std::string> base = params.get<std::string>("base");
        if (base)
            filename_ = *base + "/" + *file;
        else
            filename_ = *file;
    }
    if (!inline_string_.empty())
    {
        parse_topojson(inline_string_);
    }
    else
    {
        mapnik::util::file file(filename_);
        if (!file.open())
        {
            throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + filename_ + "'");
        }
        std::string file_buffer;
        file_buffer.resize(file.size());
        std::fread(&file_buffer[0], file.size(), 1, file.get());
        parse_topojson(file_buffer);
    }
}

namespace {
using base_iterator_type = std::string::const_iterator;
const mapnik::topojson::topojson_grammar<base_iterator_type> g;
}

template <typename T>
void topojson_datasource::parse_topojson(T const& buffer)
{
    boost::spirit::standard::space_type space;
    bool result = boost::spirit::qi::phrase_parse(buffer.begin(), buffer.end(), g, space, topo_);
    if (!result)
    {
        throw mapnik::datasource_exception("topojson_datasource: Failed parse TopoJSON file '" + filename_ + "'");
    }

    using values_container = std::vector< std::pair<box_type, std::size_t> >;
    values_container values;
    values.reserve(topo_.geometries.size());

    std::size_t geometry_index = 0;

    for (auto const& geom : topo_.geometries)
    {
        mapnik::box2d<double> box = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo_), geom);
        if (box.valid())
        {
            if (geometry_index == 0)
            {
                extent_ = box;
                collect_attributes_visitor assessor(desc_);
                mapnik::util::apply_visitor( std::ref(assessor), geom);
            }
            else
            {
                extent_.expand_to_include(box);
            }
            values.emplace_back(box, geometry_index);
        }
        ++geometry_index;
    }

    // packing algorithm
    tree_ = std::make_unique<spatial_index_type>(values);
}

topojson_datasource::~topojson_datasource() { }

const char * topojson_datasource::name()
{
    return "topojson";
}

boost::optional<mapnik::datasource_geometry_t> topojson_datasource::get_geometry_type() const
{
    boost::optional<mapnik::datasource_geometry_t> result;
    int multi_type = 0;
    std::size_t num_features = topo_.geometries.size();
    for (std::size_t i = 0; i < num_features && i < 5; ++i)
    {
        mapnik::topojson::geometry const& geom = topo_.geometries[i];
        int type = mapnik::util::apply_visitor(geometry_type_visitor(),geom);
        if (type > 0)
        {
            if (multi_type > 0 && multi_type != type)
            {
                result.reset(mapnik::datasource_geometry_t::Collection);
                return result;
            }
            else
            {
                result.reset(static_cast<mapnik::datasource_geometry_t>(type));
            }
            multi_type = type;
        }
    }
    return result;
}

mapnik::datasource::datasource_t topojson_datasource::type() const
{
    return type_;
}

mapnik::box2d<double> topojson_datasource::envelope() const
{
    return extent_;
}

mapnik::layer_descriptor topojson_datasource::get_descriptor() const
{
    return desc_;
}

mapnik::featureset_ptr topojson_datasource::features(mapnik::query const& q) const
{
    // if the query box intersects our world extent then query for features
    mapnik::box2d<double> const& box = q.get_bbox();
    if (extent_.intersects(box))
    {
        topojson_featureset::array_type index_array;
        if (tree_)
        {
            tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array));
            return std::make_shared<topojson_featureset>(topo_, *tr_, std::move(index_array));
        }
    }
    // otherwise return an empty featureset pointer
    return mapnik::featureset_ptr();
}

mapnik::featureset_ptr topojson_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
    mapnik::box2d<double> query_bbox(pt, pt);
    query_bbox.pad(tol);
    mapnik::query q(query_bbox);
    for (auto const& attr_info : desc_.get_descriptors())
    {
        q.add_property_name(attr_info.get_name());
    }
    return features(q);
}
<|endoftext|>


<commit_before>/*  -*- mode: C++; c-file-style: "gnu" -*-
    text_vcard.cpp

    This file is part of KMail, the KDE mail client.
    Copyright (c) 2004 Till Adam <adam@kde.org>

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

    KMail 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
    General Public License for more details.

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

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <qurl.h>

#include <kapplication.h>
#include <kglobal.h>
#include <klocale.h>
#include <kstringhandler.h>
#include <kglobalsettings.h>
#include <kiconloader.h>

#include <kaddrbook.h>

#include "interfaces/bodypartformatter.h"
#include "interfaces/bodypart.h"
using KMail::Interface::BodyPart;
#include "interfaces/bodyparturlhandler.h"
#include "khtmlparthtmlwriter.h"
#include <kimproxy.h>

#include <kabc/vcardconverter.h>
#include <kabc/addressee.h>
using KABC::VCardConverter;
using KABC::Addressee;

#include "addresseeview.h"
using KPIM::AddresseeView;

#include <kdepimmacros.h>

namespace {

  class Formatter : public KMail::Interface::BodyPartFormatter {
  public:
    Formatter() {
      // disabled pending resolution of how to share static objects when dlopening libraries
      //mKIMProxy = ::KIMProxy::instance( kapp->dcopClient() );
    }

    Result format( BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {

       if ( !writer ) return AsIcon;

       VCardConverter vcc;
       const QString vCard = bodyPart->asText();
       if ( vCard.isEmpty() ) return AsIcon;
       Addressee::List al = vcc.parseVCards(  vCard );
       if ( al.empty() ) return AsIcon;

       writer->queue (
             "

" +
             i18n( "Attached business cards" ) +
             "

"
                );

       QValueListIterator<KABC::Addressee> it = al.begin();
       int count = 0;
       for ( ; it != al.end(); ++it ) {
          KABC::Addressee a = (*it);
          if ( a.isEmpty() ) return AsIcon;

          QString contact = AddresseeView::vCardAsHTML( a, 0L, 0, false, true, true, true, true, true, false );
          writer->queue( contact );

          QString addToLinkText = i18n( "[Add this contact to the addressbook]" );
          QString op = QString::fromLatin1( "addToAddressBook:%1" ).arg( count );
          writer->queue(
                "
makeLink( op ) +
                "\">" +
                addToLinkText +
                "

" );
          count++;
       }

       return Ok;
    }
  private:
    //::KIMProxy *mKIMProxy;
};

  class UrlHandler : public KMail::Interface::BodyPartURLHandler {
  public:
     bool handleClick( BodyPart * bodyPart, const QString & path,
                       KMail::Callback& ) const {

       const QString vCard = bodyPart->asText();
       if ( vCard.isEmpty() ) return true;
       VCardConverter vcc;
       Addressee::List al = vcc.parseVCards(  vCard );
       int index = path.right( path.length() - path.findRev( ":" ) - 1 ).toInt();
       if ( index == -1 ) return true;
       KABC::Addressee a = al[index];
       if ( a.isEmpty() ) return true;
       KAddrBookExternal::addVCard( a, 0 );
       return true;
     }

     bool handleContextMenuRequest(  BodyPart *, const QString &, const QPoint & ) const {
       return false;
     }

     QString statusBarMessage(  BodyPart *, const QString & ) const {
       return i18n("Add this contact to the address book.");
     }
  };

  class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
  public:
    const KMail::Interface::BodyPartFormatter * bodyPartFormatter( int idx ) const {
      return idx == 0 ? new Formatter() : 0 ;
    }
    const char * type( int idx ) const {
      return idx == 0 ? "text" : 0 ;
    }
    const char * subtype( int idx ) const {
      return idx == 0 ? "x-vcard" : idx == 1 ? "vcard" : 0 ;
    }

    const KMail::Interface::BodyPartURLHandler * urlHandler( int idx ) const {
       return idx == 0 ? new UrlHandler() : 0 ;
    }
  };

}

extern "C"
KDE_EXPORT KMail::Interface::BodyPartFormatterPlugin *
libkmail_bodypartformatter_text_vcard_create_bodypart_formatter_plugin() {
  KGlobal::locale()->insertCatalogue( "kmail_text_vcard_plugin" );
  return new Plugin();
}

<commit_msg>Fix secondary subtype here as well.<commit_after>/*  -*- mode: C++; c-file-style: "gnu" -*-
    text_vcard.cpp

    This file is part of KMail, the KDE mail client.
    Copyright (c) 2004 Till Adam <adam@kde.org>

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

    KMail 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
    General Public License for more details.

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

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <qurl.h>

#include <kapplication.h>
#include <kglobal.h>
#include <klocale.h>
#include <kstringhandler.h>
#include <kglobalsettings.h>
#include <kiconloader.h>

#include <kaddrbook.h>

#include "interfaces/bodypartformatter.h"
#include "interfaces/bodypart.h"
using KMail::Interface::BodyPart;
#include "interfaces/bodyparturlhandler.h"
#include "khtmlparthtmlwriter.h"
#include <kimproxy.h>

#include <kabc/vcardconverter.h>
#include <kabc/addressee.h>
using KABC::VCardConverter;
using KABC::Addressee;

#include "addresseeview.h"
using KPIM::AddresseeView;

#include <kdepimmacros.h>

namespace {

  class Formatter : public KMail::Interface::BodyPartFormatter {
  public:
    Formatter() {
      // disabled pending resolution of how to share static objects when dlopening libraries
      //mKIMProxy = ::KIMProxy::instance( kapp->dcopClient() );
    }

    Result format( BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {

       if ( !writer ) return AsIcon;

       VCardConverter vcc;
       const QString vCard = bodyPart->asText();
       if ( vCard.isEmpty() ) return AsIcon;
       Addressee::List al = vcc.parseVCards(  vCard );
       if ( al.empty() ) return AsIcon;

       writer->queue (
             "

" +
             i18n( "Attached business cards" ) +
             "

"
                );

       QValueListIterator<KABC::Addressee> it = al.begin();
       int count = 0;
       for ( ; it != al.end(); ++it ) {
          KABC::Addressee a = (*it);
          if ( a.isEmpty() ) return AsIcon;

          QString contact = AddresseeView::vCardAsHTML( a, 0L, 0, false, true, true, true, true, true, false );
          writer->queue( contact );

          QString addToLinkText = i18n( "[Add this contact to the addressbook]" );
          QString op = QString::fromLatin1( "addToAddressBook:%1" ).arg( count );
          writer->queue(
                "
makeLink( op ) +
                "\">" +
                addToLinkText +
                "

" );
          count++;
       }

       return Ok;
    }
  private:
    //::KIMProxy *mKIMProxy;
};

  class UrlHandler : public KMail::Interface::BodyPartURLHandler {
  public:
     bool handleClick( BodyPart * bodyPart, const QString & path,
                       KMail::Callback& ) const {

       const QString vCard = bodyPart->asText();
       if ( vCard.isEmpty() ) return true;
       VCardConverter vcc;
       Addressee::List al = vcc.parseVCards(  vCard );
       int index = path.right( path.length() - path.findRev( ":" ) - 1 ).toInt();
       if ( index == -1 ) return true;
       KABC::Addressee a = al[index];
       if ( a.isEmpty() ) return true;
       KAddrBookExternal::addVCard( a, 0 );
       return true;
     }

     bool handleContextMenuRequest(  BodyPart *, const QString &, const QPoint & ) const {
       return false;
     }

     QString statusBarMessage(  BodyPart *, const QString & ) const {
       return i18n("Add this contact to the address book.");
     }
  };

  class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
  public:
    const KMail::Interface::BodyPartFormatter * bodyPartFormatter( int idx ) const {
      return validIndex( idx ) ? new Formatter() : 0 ;
    }
    const char * type( int idx ) const {
      return validIndex( idx ) ? "text" : 0 ;
    }
    const char * subtype( int idx ) const {
      return idx == 0 ? "x-vcard" : idx == 1 ? "vcard" : 0 ;
    }

    const KMail::Interface::BodyPartURLHandler * urlHandler( int idx ) const {
       return validIndex( idx ) ? new UrlHandler() : 0 ;
    }
  private:
    bool validIndex( int idx ) const {
      return ( idx >= 0 && idx <= 1 );
    }
  };

}

extern "C"
KDE_EXPORT KMail::Interface::BodyPartFormatterPlugin *
libkmail_bodypartformatter_text_vcard_create_bodypart_formatter_plugin() {
  KGlobal::locale()->insertCatalogue( "kmail_text_vcard_plugin" );
  return new Plugin();
}

<|endoftext|>


<commit_before>#include <regex>
#include "foo_musicbrainz.h"
#include "RequestURL.h"
#include "TOC.h"
#include "Track.h"
#include "QueryByMBIDDialog.h"
#include "QueryByTagsDialog.h"
#include "TaggerDialog.h"

using namespace std::tr1;
using namespace foo_musicbrainz;

namespace foo_musicbrainz {
	class ContextMenu : public contextmenu_item_simple {
	public:
		unsigned get_num_items() {
			return 4;
		}

		void get_item_name(unsigned p_index, pfc::string_base & p_out) {
			static const char *item_name[] = {
				"Get Tags From MusicBrainz (by TOC)",
				"Get Tags From MusicBrainz (by Artist & Album)",
				"Get Tags From MusicBrainz (by MusicBrainz Album ID)",
				"Add TOC to MusicBrainz"
			};
			p_out = item_name[p_index];
		}

		void get_item_default_path(unsigned p_index, pfc::string_base & p_out) {
			p_out = "Tagging";
		}

		void context_command(unsigned p_index, metadb_handle_list_cref p_data, const GUID& p_caller) {
			unsigned int count = p_data.get_count();
			if (p_index <= 2 && count > 99) {
				popup_message::g_show("Please select no more than 99 tracks.", COMPONENT_TITLE, popup_message::icon_error);
				return;
			}
			switch (p_index) {
				case 0: {
					TOC toc(p_data);
					RequestURL url;
					url.AddParam("discid", toc.getDiscID());
					url.AddParam("count", count);
					url.AddParam("cdstubs", "no");

					pfc::list_t<metadb_handle_ptr> tracks;
					tracks.add_items(p_data);
					pfc::string8 discid(toc.getDiscID());

					// new TaggerDialog(url.GetURL(), mbc);
					break;
				}
				case 1: {
					pfc::string8 artist, album;
					for (t_size i = 0; i < count; i++) {
						auto item = p_data.get_item(i);
						item->metadb_lock();
						const file_info *info;
						if (!item->get_info_locked(info)) {
							item->metadb_unlock();
							return;
						}

						auto current_artist = info->meta_get("ALBUM ARTIST", 0);
						if (current_artist == nullptr) current_artist = info->meta_get("ARTIST", 0);
						auto current_album = info->meta_get("ALBUM", 0);

						if (current_artist == nullptr || current_album == nullptr) {
							item->metadb_unlock();
							break;
						}

						// Save album and artist of the first item
						if (i == 0) {
							artist = current_artist;
							album = current_album;
							if (artist.is_empty() || album.is_empty()) {
								artist.reset();
								album.reset();
								item->metadb_unlock();
								break;
							}
						// Break if artist or album of current item are different from the first one
						} else if (strcmp(artist, current_artist) != 0 || strcmp(album, current_album) != 0) {
							artist.reset();
							album.reset();
							item->metadb_unlock();
								break;
						}
						item->metadb_unlock();
					}
					pfc::list_t<metadb_handle_ptr> tracks;
					tracks.add_items(p_data);
					new QueryByTagsDialog(tracks, artist, album);
					break;
				}
				case 2: {
					// Stop if MBIDs are disabled
					if (!Preferences::write_ids.get_value()) return;

					pfc::string8 album_id;
					for (t_size i = 0; i < count; i++) {
						auto item = p_data.get_item(i);
						item->metadb_lock();
						const file_info *info;
						if (!item->get_info_locked(info)) {
							item->metadb_unlock();
							return;
						}

						auto current_album_id = info->meta_get("MUSICBRAINZ_ALBUMID", 0);

						if (current_album_id == nullptr) {
							item->metadb_unlock();
							break;
						}

						// Save album ID of the first item
						if (i == 0) {
							album_id = current_album_id;
							regex rx("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
							if (!regex_search(album_id.get_ptr(), rx)) {
								album_id.reset();
								item->metadb_unlock();
								break;
							}
						// Break if album ID of current item is different from the first one
						} else if (strcmp(album_id, current_album_id) != 0) {
							album_id.reset();
							item->metadb_unlock();
							break;
						}
						item->metadb_unlock();
					}
					pfc::list_t<metadb_handle_ptr> tracks;
					tracks.add_items(p_data);
					new QueryByMBIDDialog(tracks, album_id);
					break;
				}
				case 3: {
					TOC toc(p_data);

					pfc::string8 url = "http://musicbrainz.org/cdtoc/attach?toc=";
					url << toc.getTOC();
					pfc::stringcvt::string_os_from_utf8 url_converter(url);
					ShellExecute(nullptr, _T("open"), url_converter, nullptr, nullptr, SW_SHOW);
					break;
				}
			}
		}

		GUID get_item_guid(unsigned p_index) {
			static const GUID guid_foo_mb_menu[] = {
				{ 0x3ca8395b, 0x694e, 0x4845, { 0xb5, 0xea, 0x56, 0x30, 0x5e, 0x7c, 0x24, 0x48 } },
				{ 0x77f1f5cd, 0xf295, 0x4ef4, { 0xba, 0x7b, 0xc7, 0x70, 0xaa, 0xc6, 0xd0, 0x1e } },
				{ 0xf453e537, 0x01e9, 0x4f2d, { 0x89, 0xdc, 0x42, 0x4d, 0x0e, 0xe5, 0x72, 0xfb } },
				{ 0x4d5e632c, 0x34f3, 0x4fda, { 0x8f, 0x71, 0x35, 0xa4, 0xb2, 0x5b, 0xea, 0x94 } }
			};
			return guid_foo_mb_menu[p_index];
		}

		bool get_item_description(unsigned p_index, pfc::string_base & p_out) {
			static const char *item_description[] = {
				"Queries MusicBrainz server for tags for a complete CD using TOC.",
				"Queries MusicBrainz server for tags for a complete CD using Artist/Album.",
				"Queries MusicBrainz server for tags for a complete CD using MusicBrainz Album ID.",
				"Opens MusicBrainz TOC lookup page."
			};
			p_out = item_description[p_index];
			return true;
		}

		bool context_get_display(unsigned p_index, metadb_handle_list_cref p_data, pfc::string_base & p_out, unsigned & p_displayflags, const GUID & p_caller) {
			PFC_ASSERT(p_index>=0 && p_index<get_num_items());
			unsigned int count = p_data.get_count();
			if (count <= 99) {
				if (p_index == 0 || p_index == 3) {
					const file_info *info;
					for (t_size i = 0; i < count; i++) {
						p_data.get_item(i)->metadb_lock();
						if (!p_data.get_item(i)->get_info_locked(info) || info->info_get_length_samples() % 588 != 0) {
							p_data.get_item(i)->metadb_unlock();
							return false;
						}
						p_data.get_item(i)->metadb_unlock();
					}
				}
				if (p_index == 2 && !Preferences::write_ids.get_value()) {
					return false;
				}
				get_item_name(p_index, p_out);
				return true;
			} else {
				return false;
			}
		}
	};

	contextmenu_item_factory_t<ContextMenu> _;
}

<commit_msg>Several tagging operations are now possible when more than 99 tracks are selected<commit_after>#include <regex>
#include "foo_musicbrainz.h"
#include "RequestURL.h"
#include "TOC.h"
#include "Track.h"
#include "QueryByMBIDDialog.h"
#include "QueryByTagsDialog.h"
#include "TaggerDialog.h"

using namespace std::tr1;
using namespace foo_musicbrainz;

namespace foo_musicbrainz {
	class ContextMenu : public contextmenu_item_simple {
	public:
		unsigned get_num_items() {
			return 4;
		}

		void get_item_name(unsigned p_index, pfc::string_base & p_out) {
			static const char *item_name[] = {
				"Get Tags From MusicBrainz (by TOC)",
				"Get Tags From MusicBrainz (by Artist & Album)",
				"Get Tags From MusicBrainz (by MusicBrainz Album ID)",
				"Add TOC to MusicBrainz"
			};
			p_out = item_name[p_index];
		}

		void get_item_default_path(unsigned p_index, pfc::string_base & p_out) {
			p_out = "Tagging";
		}

		void context_command(unsigned p_index, metadb_handle_list_cref p_data, const GUID& p_caller) {
			unsigned int count = p_data.get_count();
			if ((p_index == 0 || p_index == 3) && count > 99) {
				popup_message::g_show("Please select no more than 99 tracks.", COMPONENT_TITLE, popup_message::icon_error);
				return;
			}
			switch (p_index) {
				case 0: {
					TOC toc(p_data);
					RequestURL url;
					url.AddParam("discid", toc.getDiscID());
					url.AddParam("count", count);
					url.AddParam("cdstubs", "no");

					pfc::list_t<metadb_handle_ptr> tracks;
					tracks.add_items(p_data);
					pfc::string8 discid(toc.getDiscID());

					// new TaggerDialog(url.GetURL(), mbc);
					break;
				}
				case 1: {
					pfc::string8 artist, album;
					for (t_size i = 0; i < count; i++) {
						auto item = p_data.get_item(i);
						item->metadb_lock();
						const file_info *info;
						if (!item->get_info_locked(info)) {
							item->metadb_unlock();
							return;
						}

						auto current_artist = info->meta_get("ALBUM ARTIST", 0);
						if (current_artist == nullptr) current_artist = info->meta_get("ARTIST", 0);
						auto current_album = info->meta_get("ALBUM", 0);

						if (current_artist == nullptr || current_album == nullptr) {
							item->metadb_unlock();
							break;
						}

						// Save album and artist of the first item
						if (i == 0) {
							artist = current_artist;
							album = current_album;
							if (artist.is_empty() || album.is_empty()) {
								artist.reset();
								album.reset();
								item->metadb_unlock();
								break;
							}
						// Break if artist or album of current item are different from the first one
						} else if (strcmp(artist, current_artist) != 0 || strcmp(album, current_album) != 0) {
							artist.reset();
							album.reset();
							item->metadb_unlock();
								break;
						}
						item->metadb_unlock();
					}
					pfc::list_t<metadb_handle_ptr> tracks;
					tracks.add_items(p_data);
					new QueryByTagsDialog(tracks, artist, album);
					break;
				}
				case 2: {
					// Stop if MBIDs are disabled
					if (!Preferences::write_ids.get_value()) return;

					pfc::string8 album_id;
					for (t_size i = 0; i < count; i++) {
						auto item = p_data.get_item(i);
						item->metadb_lock();
						const file_info *info;
						if (!item->get_info_locked(info)) {
							item->metadb_unlock();
							return;
						}

						auto current_album_id = info->meta_get("MUSICBRAINZ_ALBUMID", 0);

						if (current_album_id == nullptr) {
							item->metadb_unlock();
							break;
						}

						// Save album ID of the first item
						if (i == 0) {
							album_id = current_album_id;
							regex rx("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
							if (!regex_search(album_id.get_ptr(), rx)) {
								album_id.reset();
								item->metadb_unlock();
								break;
							}
						// Break if album ID of current item is different from the first one
						} else if (strcmp(album_id, current_album_id) != 0) {
							album_id.reset();
							item->metadb_unlock();
							break;
						}
						item->metadb_unlock();
					}
					pfc::list_t<metadb_handle_ptr> tracks;
					tracks.add_items(p_data);
					new QueryByMBIDDialog(tracks, album_id);
					break;
				}
				case 3: {
					TOC toc(p_data);

					pfc::string8 url = "http://musicbrainz.org/cdtoc/attach?toc=";
					url << toc.getTOC();
					pfc::stringcvt::string_os_from_utf8 url_converter(url);
					ShellExecute(nullptr, _T("open"), url_converter, nullptr, nullptr, SW_SHOW);
					break;
				}
			}
		}

		GUID get_item_guid(unsigned p_index) {
			static const GUID guid_foo_mb_menu[] = {
				{ 0x3ca8395b, 0x694e, 0x4845, { 0xb5, 0xea, 0x56, 0x30, 0x5e, 0x7c, 0x24, 0x48 } },
				{ 0x77f1f5cd, 0xf295, 0x4ef4, { 0xba, 0x7b, 0xc7, 0x70, 0xaa, 0xc6, 0xd0, 0x1e } },
				{ 0xf453e537, 0x01e9, 0x4f2d, { 0x89, 0xdc, 0x42, 0x4d, 0x0e, 0xe5, 0x72, 0xfb } },
				{ 0x4d5e632c, 0x34f3, 0x4fda, { 0x8f, 0x71, 0x35, 0xa4, 0xb2, 0x5b, 0xea, 0x94 } }
			};
			return guid_foo_mb_menu[p_index];
		}

		bool get_item_description(unsigned p_index, pfc::string_base & p_out) {
			static const char *item_description[] = {
				"Queries MusicBrainz server for tags for a complete CD using TOC.",
				"Queries MusicBrainz server for tags for a complete CD using Artist/Album.",
				"Queries MusicBrainz server for tags for a complete CD using MusicBrainz Album ID.",
				"Opens MusicBrainz TOC lookup page."
			};
			p_out = item_description[p_index];
			return true;
		}

		bool context_get_display_toc(metadb_handle_list_cref p_data) {
			t_size count = p_data.get_count();
			if (count > 99) {
				return false;
			}
			const file_info *info;
			for (t_size i = 0; i < count; i++) {
				p_data.get_item(i)->metadb_lock();
				if (!p_data.get_item(i)->get_info_locked(info) || info->info_get_length_samples() % 588 != 0) {
					p_data.get_item(i)->metadb_unlock();
					return false;
				}
				p_data.get_item(i)->metadb_unlock();
			}
			return true;
		}

		bool context_get_display_tags(unsigned p_idex) {
			return Preferences::write_ids.get_value();
		}

		bool context_get_display(unsigned p_index, metadb_handle_list_cref p_data, pfc::string_base & p_out, unsigned & p_displayflags, const GUID & p_caller) {
			PFC_ASSERT(p_index>=0 && p_index<get_num_items());
			bool result = true;
			switch (p_index) {
			case 0:
				result = context_get_display_toc(p_data);
				break;
			case 1:
				result = context_get_display_tags(p_index);
				break;
			case 3:
				result = context_get_display_toc(p_data);
				break;
			}
			if (result) {
				get_item_name(p_index, p_out);
			}
			return result;
		}
	};

	contextmenu_item_factory_t<ContextMenu> _;
}

<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright 2016 [bk]door.maus

#include <cassert>
#include <memory>
#include <assimp/Exporter.hpp>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include "glurg/resources/mesh/meshResource.hpp"
#include "glurg/resources/mesh/meshResourceBlob.hpp"
#include "glurg/resources/mesh/model.hpp"
#include "glurg/resources/mesh/modelExporter.hpp"

glurg::ModelExporter::ModelExporter()
{
	this->model = nullptr;
}

const glurg::Model* glurg::ModelExporter::get_model() const
{
	return this->model;
}

void glurg::ModelExporter::set_model(const Model* value)
{
	this->model = value;
}

void populate_positions(aiMesh* mesh, const glurg::MeshResource* positions)
{
	if (positions == nullptr)
	{
		throw std::runtime_error("model incomplete; has no vertex positions");
	}
	else
	{
		const std::size_t num_values = positions->get_num_values();
		mesh->mNumVertices = num_values;
		mesh->mVertices = new aiVector3D[num_values];

		for (std::size_t i = 0; i < num_values; ++i)
		{
			auto v = positions->get_value(i);
			mesh->mVertices[i].x = v.x;
			mesh->mVertices[i].y = v.y;
			mesh->mVertices[i].z = v.z;
		}
	}
}

void populate_index_data(aiMesh* mesh, const glurg::Model* model)
{
	if (model->get_index_data_type() != glurg::Model::index_format_none)
	{
		const std::size_t index_data_count =
			model->get_index_data_count();
		assert(index_data_count % 3 == 0);

		mesh->mNumFaces = index_data_count / 3;
		mesh->mFaces = new aiFace[mesh->mNumFaces];

		auto index_data = model->get_index_data();
		for (std::size_t i = 0; i < mesh->mNumFaces; ++i)
		{
			mesh->mFaces[i].mIndices = new unsigned int[3];
			mesh->mFaces[i].mNumIndices = 3;

			for (std::size_t j = 0; j < 3; ++j)
			{
				switch (model->get_index_data_type())
				{
					case glurg::Model::index_format_unsigned_byte:
						mesh->mFaces[i].mIndices[j] = *index_data;
						index_data += sizeof(std::uint8_t);
						break;
					case glurg::Model::index_format_unsigned_short:
						mesh->mFaces[i].mIndices[j] =
							*((const std::uint16_t*)index_data);
						index_data += sizeof(std::uint16_t);
						break;
					case glurg::Model::index_format_unsigned_integer:
						mesh->mFaces[i].mIndices[j] =
							*((const std::uint32_t*)index_data);
						index_data += sizeof(std::uint32_t);
						break;
					default:
						assert(false);
				}
			}
		}
	}
}

void populate_generic_data(
	std::size_t num_vertices,
	aiVector3D*& output_data, const glurg::MeshResource* input_data)
{
	if (input_data->get_num_values() != num_vertices)
	{
		throw std::runtime_error("vertex data size mismatch");
	}

	output_data = new aiVector3D[num_vertices];
	for (std::size_t i = 0; i < num_vertices; ++i)
	{
		auto v = input_data->get_value(i);
		output_data[i].x = v.x;
		output_data[i].y = v.y;
		output_data[i].z = v.z;
	}
}

void glurg::ModelExporter::to_dae(Buffer& output_buffer)
{
	if (this->model == nullptr)
	{
		throw std::runtime_error("no model to export");
	}

	std::unique_ptr<aiMesh> mesh(new aiMesh());
	const std::size_t num_vertices =
		this->model->get_mesh_positions()->get_num_values();

	populate_positions(mesh.get(), this->model->get_mesh_positions());
	populate_index_data(mesh.get(), this->model);

	if (this->model->get_mesh_normals() != nullptr)
	{
		populate_generic_data(
			num_vertices, mesh->mNormals, this->model->get_mesh_normals());
	}

	if (this->model->get_num_mesh_texture_coordinates() != 0)
	{
		const std::size_t num_texture_coordinates =
			this->model->get_num_mesh_texture_coordinates();

		for (std::size_t i = 0; i < num_texture_coordinates; ++i)
		{
			auto texture_coordinates =
				this->model->get_mesh_texture_coordinates(i);
			if (texture_coordinates == nullptr)
			{
				throw std::runtime_error("expected valid texture coordinates");
			}

			mesh->mNumUVComponents[i] =
				((MeshResourceBlob*)texture_coordinates->get_blob())
					->get_vertex_description()
					.num_components;
			populate_generic_data(
				num_vertices, mesh->mTextureCoords[i], texture_coordinates);
		}
	}

	if (this->model->get_num_mesh_colors() != 0)
	{
		const std::size_t num_colors = this->model->get_num_mesh_colors();
		if (num_colors > AI_MAX_NUMBER_OF_COLOR_SETS)
		{
			throw std::runtime_error("number of color channels exceeds max");
		}

		for (std::size_t i = 0; i < num_colors; ++i)
		{
			auto colors = this->model->get_mesh_colors(i);
			if (colors == nullptr)
			{
				throw std::runtime_error("expect valid colors");
			}

			populate_generic_data(
				num_vertices, mesh->mTextureCoords[i], colors);
		}
	}

	std::unique_ptr<aiScene> scene(new aiScene());
	scene->mNumMeshes = 1;
	scene->mMeshes = new aiMesh*[1];
	scene->mMeshes[0] = mesh.release();

	std::unique_ptr<Assimp::Exporter> exporter(new Assimp::Exporter());
	auto blob = exporter->ExportToBlob(scene.get(), "dae", 0);

	output_buffer.insert(output_buffer.end(),
		(std::uint8_t*)blob->data, (std::uint8_t*)blob->data + blob->size);
}
<commit_msg>Fixed up model export code.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright 2016 [bk]door.maus

#include <cassert>
#include <memory>
#include <assimp/Exporter.hpp>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include "glurg/resources/mesh/meshResource.hpp"
#include "glurg/resources/mesh/meshResourceBlob.hpp"
#include "glurg/resources/mesh/model.hpp"
#include "glurg/resources/mesh/modelExporter.hpp"

glurg::ModelExporter::ModelExporter()
{
	this->model = nullptr;
}

const glurg::Model* glurg::ModelExporter::get_model() const
{
	return this->model;
}

void glurg::ModelExporter::set_model(const Model* value)
{
	this->model = value;
}

void populate_positions(aiMesh* mesh, const glurg::MeshResource* positions)
{
	if (positions == nullptr)
	{
		throw std::runtime_error("model incomplete; has no vertex positions");
	}
	else
	{
		const std::size_t num_values = positions->get_num_values();
		mesh->mNumVertices = num_values;
		mesh->mVertices = new aiVector3D[num_values];

		for (std::size_t i = 0; i < num_values; ++i)
		{
			auto v = positions->get_value(i);
			mesh->mVertices[i].x = v.x;
			mesh->mVertices[i].y = v.y;
			mesh->mVertices[i].z = v.z;
		}
	}
}

void populate_index_data(aiMesh* mesh, const glurg::Model* model)
{
	if (model->get_index_data_type() != glurg::Model::index_format_none)
	{
		const std::size_t index_data_count =
			model->get_index_data_count();
		assert(index_data_count % 3 == 0);

		mesh->mNumFaces = index_data_count / 3;
		mesh->mFaces = new aiFace[mesh->mNumFaces];

		auto index_data = model->get_index_data();
		for (std::size_t i = 0; i < mesh->mNumFaces; ++i)
		{
			mesh->mFaces[i].mIndices = new unsigned int[3];
			mesh->mFaces[i].mNumIndices = 3;

			for (std::size_t j = 0; j < 3; ++j)
			{
				switch (model->get_index_data_type())
				{
					case glurg::Model::index_format_unsigned_byte:
						mesh->mFaces[i].mIndices[j] = *index_data;
						index_data += sizeof(std::uint8_t);
						break;
					case glurg::Model::index_format_unsigned_short:
						mesh->mFaces[i].mIndices[j] =
							*((const std::uint16_t*)index_data);
						index_data += sizeof(std::uint16_t);
						break;
					case glurg::Model::index_format_unsigned_integer:
						mesh->mFaces[i].mIndices[j] =
							*((const std::uint32_t*)index_data);
						index_data += sizeof(std::uint32_t);
						break;
					default:
						assert(false);
				}
			}
		}
	}
}

void populate_generic_data(
	std::size_t num_vertices,
	aiVector3D*& output_data, const glurg::MeshResource* input_data)
{
	if (input_data->get_num_values() != num_vertices)
	{
		throw std::runtime_error("vertex data size mismatch");
	}

	output_data = new aiVector3D[num_vertices];
	for (std::size_t i = 0; i < num_vertices; ++i)
	{
		auto v = input_data->get_value(i);
		output_data[i].x = v.x;
		output_data[i].y = v.y;
		output_data[i].z = v.z;
	}
}

void glurg::ModelExporter::to_dae(Buffer& output_buffer)
{
	if (this->model == nullptr)
	{
		throw std::runtime_error("no model to export");
	}

	std::unique_ptr<aiMesh> mesh(new aiMesh());
	const std::size_t num_vertices =
		this->model->get_mesh_positions()->get_num_values();

	populate_positions(mesh.get(), this->model->get_mesh_positions());
	populate_index_data(mesh.get(), this->model);

	if (this->model->get_mesh_normals() != nullptr)
	{
		populate_generic_data(
			num_vertices, mesh->mNormals, this->model->get_mesh_normals());
	}

	if (this->model->get_num_mesh_texture_coordinates() != 0)
	{
		const std::size_t num_texture_coordinates =
			this->model->get_num_mesh_texture_coordinates();

		for (std::size_t i = 0; i < num_texture_coordinates; ++i)
		{
			auto texture_coordinates =
				this->model->get_mesh_texture_coordinates(i);
			if (texture_coordinates == nullptr)
			{
				throw std::runtime_error("expected valid texture coordinates");
			}

			mesh->mNumUVComponents[i] =
				((MeshResourceBlob*)texture_coordinates->get_blob())
					->get_vertex_description()
					.num_components;
			populate_generic_data(
				num_vertices, mesh->mTextureCoords[i], texture_coordinates);
		}
	}

	if (this->model->get_num_mesh_colors() != 0)
	{
		const std::size_t num_colors = this->model->get_num_mesh_colors();
		if (num_colors > AI_MAX_NUMBER_OF_COLOR_SETS)
		{
			throw std::runtime_error("number of color channels exceeds max");
		}

		for (std::size_t i = 0; i < num_colors; ++i)
		{
			auto colors = this->model->get_mesh_colors(i);
			if (colors == nullptr)
			{
				throw std::runtime_error("expect valid colors");
			}

			populate_generic_data(
				num_vertices, mesh->mTextureCoords[i], colors);
		}
	}

	std::unique_ptr<aiScene> scene(new aiScene());
	scene->mNumMeshes = 1;
	scene->mMeshes = new aiMesh*[1];
	scene->mMeshes[0] = mesh.release();
	scene->mNumMaterials = 1;
	scene->mMaterials = new aiMaterial*[1];
	scene->mMaterials[0] = new aiMaterial();
	scene->mRootNode = new aiNode();
	scene->mRootNode->mName = "root";
	scene->mRootNode->mNumMeshes = 1;
	scene->mRootNode->mMeshes = new std::uint32_t[1];
	scene->mRootNode->mMeshes[0] = 0;

	std::unique_ptr<Assimp::Exporter> exporter(new Assimp::Exporter());
	auto blob = exporter->ExportToBlob(scene.get(), "collada", 0);

	if (blob == nullptr)
	{
		throw std::runtime_error("couldn't export model");
	}

	output_buffer.insert(output_buffer.end(),
		(std::uint8_t*)blob->data, (std::uint8_t*)blob->data + blob->size);
}
<|endoftext|>