<commit_before>#include "SyncThread.h"
#include "common/RhoTime.h"
#include "common/RhoConf.h"
#include "common/RhoFilePath.h"

#include "ruby/ext/rho/rhoruby.h"

namespace rho {
namespace sync {

using namespace rho::common;
using namespace rho::db;

IMPLEMENT_LOGCLASS(CSyncThread,"Sync");
CSyncThread* CSyncThread::m_pInstance = 0;

/*static*/ CSyncThread* CSyncThread::Create(common::IRhoClassFactory* factory)
{
    if ( m_pInstance )
        return m_pInstance;

    m_pInstance = new CSyncThread(factory);
    return m_pInstance;
}

/*static*/void CSyncThread::Destroy()
{
    if ( m_pInstance )
        delete m_pInstance;

    m_pInstance = 0;
}

CSyncThread::CSyncThread(common::IRhoClassFactory* factory) : CThreadQueue(factory)
{
    CThreadQueue::setLogCategory(getLogCategory());

    if( RHOCONF().isExist("sync_poll_interval") )
        setPollInterval(RHOCONF().getInt("sync_poll_interval"));

    m_oSyncEngine.setFactory(factory);

    if ( RHOCONF().getString("syncserver").length() > 0 )
        start(epLow);
}

CSyncThread::~CSyncThread(void)
{
    m_oSyncEngine.exitSync();
    stop(SYNC_WAIT_BEFOREKILL_SECONDS);

    db::CDBAdapter::closeAll();

    LOG(INFO) + "Sync engine thread shutdown";
}

int CSyncThread::getLastPollInterval()
{
    uint64 nowTime = CLocalTime().toULong();

    DBResult( res, CDBAdapter::getUserDB().executeSQL("SELECT last_updated from sources") );
    uint64 latestTimeUpdated = 0;
    for ( ; !res.isEnd(); res.next() )
    {
        uint64 timeUpdated = res.getUInt64ByIdx(0);
        if ( latestTimeUpdated < timeUpdated )
        	latestTimeUpdated = timeUpdated;
    }

	return latestTimeUpdated > 0 ? (int)(nowTime-latestTimeUpdated) : 0;
}

void CSyncThread::processCommands()//throws Exception
{
    if ( isNoCommands() )
        addQueueCommand(new CSyncCommand(scNone,false));

    CThreadQueue::processCommands();
}

void CSyncThread::checkShowStatus(CSyncCommand& oSyncCmd)
{
	boolean bShowStatus = oSyncCmd.m_bShowStatus;
	m_oSyncEngine.getNotify().enableReporting(bShowStatus);
	//if (bShowStatus)
		//m_statusListener.createStatusPopup(RhoRuby.getMessageText("syncronizing_data"));
}

void CSyncThread::processCommand(CQueueCommand* pCmd)
{
    CSyncCommand& oSyncCmd = *((CSyncCommand*)pCmd);
    switch(oSyncCmd.m_nCmdCode)
    {
    case scNone:
        if ( getPollInterval() )
        {
            checkShowStatus(oSyncCmd);
            m_oSyncEngine.doSyncAllSources();
        }
        break;
    case scSyncAll:
        checkShowStatus(oSyncCmd);
        m_oSyncEngine.doSyncAllSources();
        break;
    case scSyncOne:
        {
			checkShowStatus(oSyncCmd);
            m_oSyncEngine.doSyncSource(CSyncEngine::CSourceID(oSyncCmd.m_nCmdParam,oSyncCmd.m_strCmdParam));
        }
        break;
    case scSearchOne:
        {
			checkShowStatus(oSyncCmd);
            m_oSyncEngine.doSearch( ((CSyncSearchCommand&)oSyncCmd).m_arSources, oSyncCmd.m_strCmdParam,
                ((CSyncSearchCommand&)oSyncCmd).m_strFrom, ((CSyncSearchCommand&)oSyncCmd).m_bSyncChanges,
                oSyncCmd.m_nCmdParam);
        }
        break;
    case scLogin:
    	{
    		CSyncLoginCommand& oLoginCmd = (CSyncLoginCommand&)oSyncCmd;

            checkShowStatus(oSyncCmd);
    		m_oSyncEngine.login(oLoginCmd.m_strName, oLoginCmd.m_strPassword, oLoginCmd.m_strCmdParam );
    	}
        break;
    }
}

void CSyncThread::setPollInterval(int nInterval)
{
    if ( nInterval == 0 )
        m_oSyncEngine.stopSync();

    CThreadQueue::setPollInterval(nInterval);
}

};
};

extern "C" {

using namespace rho::sync;
using namespace rho::db;
void rho_sync_destroy()
{
	CSyncThread::Destroy();
}

void rho_sync_doSyncAllSources(int show_status_popup)
{
    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncCommand(CSyncThread::scSyncAll,show_status_popup!=0));
    //rho_sync_doSyncSourceByUrl("http://dev.rhosync.rhohub.com/apps/SugarCRM/sources/SugarAccounts");
}

void rho_sync_doSyncSource(unsigned long nSrcID,int show_status_popup)
{
    CRhoRubyStringOrInt oSrcID = rho_ruby_getstringorint(nSrcID);
    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncCommand(CSyncThread::scSyncOne, oSrcID.m_szStr, (int)oSrcID.m_nInt, show_status_popup!=0 ) );
}

void rho_sync_stop()
{
	if (CSyncThread::getSyncEngine().isSyncing() )
	{
		CSyncThread::getSyncEngine().stopSyncByUser();
        CSyncThread::getInstance()->stopWait();

        while( CDBAdapter::isAnyInsideTransaction() )
			CSyncThread::getInstance()->sleep(100);
	}
}

extern "C" void
source_iter(const char* szName, void* parSources)
{
    rho::Vector<rho::String>& arSources = *((rho::Vector<rho::String>*)(parSources));
    arSources.addElement(szName);
}

void rho_sync_doSearch(unsigned long ar_sources, const char *from, const char *params, bool sync_changes, int nProgressStep,
    const char* callback, const char* callback_params)
{
    rho_sync_stop();
    if ( callback && *callback )
        CSyncThread::getSyncEngine().getNotify().setSearchNotification( callback, callback_params ? callback_params : "");

    rho::Vector<rho::String> arSources;
    rho_ruby_enum_strary(ar_sources, source_iter, &arSources);

    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncSearchCommand(from,params,arSources,sync_changes,nProgressStep) );
}

void rho_sync_doSyncSourceByUrl(const char* szSrcUrl)
{
    const char* szLastSlash = strrchr(szSrcUrl, '\\');
    if ( !szLastSlash )
        szLastSlash = strrchr(szSrcUrl, '/');

    const char* szQuest = strrchr(szSrcUrl, '?');

    rho::String strName = "";
    if (szQuest && szLastSlash)
        strName = rho::String(szLastSlash+1, szQuest-szLastSlash-1);
    else
        strName = szLastSlash ? szLastSlash + 1 : szSrcUrl;

    //TODO: save query params
    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncCommand(CSyncThread::scSyncOne, strName, (int)0, false ) );
}

void rho_sync_set_pollinterval(int nInterval)
{
    CSyncThread::getInstance()->setPollInterval(nInterval);
}

void rho_sync_set_syncserver(char* syncserver)
{
    rho_sync_stop();

	CSyncThread::getSyncEngine().setSyncServer(syncserver);

    if ( syncserver && *syncserver )
        CSyncThread::getInstance()->start(CSyncThread::epLow);
    else
        CSyncThread::getInstance()->stop(CSyncThread::SYNC_WAIT_BEFOREKILL_SECONDS);
}

void rho_sync_login(const char *name, const char *password, const char* callback)
{
    rho_sync_stop();
    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncLoginCommand(name, password, callback) );
}

int rho_sync_logged_in()
{
	CDBAdapter& db = CDBAdapter::getUserDB();
    return CSyncThread::getSyncEngine().isLoggedIn() ? 1 : 0;
}

void rho_sync_logout()
{
    rho_sync_stop();

	CDBAdapter& db = CDBAdapter::getUserDB();
    CSyncThread::getSyncEngine().logout();
}

void rho_sync_set_notification(int source_id, const char *url, char* params)
{
    return CSyncThread::getSyncEngine().getNotify().setSyncNotification(source_id, url, params ? params : "");
}

void rho_sync_clear_notification(int source_id)
{
    return CSyncThread::getSyncEngine().getNotify().clearSyncNotification(source_id);
}

void rho_sync_set_bulk_notification(const char *url, char* params)
{
    return CSyncThread::getSyncEngine().getNotify().setBulkSyncNotification(url, params ? params : "");
}

void rho_sync_clear_bulk_notification()
{
    return CSyncThread::getSyncEngine().getNotify().clearBulkSyncNotification();
}

unsigned long rho_sync_get_attrs(const char* szPartition, int nSrcID)
{
    return (VALUE)CDBAdapter::getDB(szPartition).getAttrMgr().getAttrsBySrc(nSrcID);
}

unsigned long rho_sync_is_blob_attr(const char* szPartition, int nSrcID, const char* szAttrName)
{
    return rho_ruby_create_boolean( CDBAdapter::getDB(szPartition).getAttrMgr().isBlobAttr(nSrcID, szAttrName) );
}

void rho_sync_setobjectnotify_url(const char* szUrl)
{
    CSyncNotify::setObjectNotifyUrl(szUrl);
}

void rho_sync_addobjectnotify(int nSrcID, const char* szObject)
{
    CSyncThread::getSyncEngine().getNotify().addObjectNotify(nSrcID, szObject);
}

void rho_sync_addobjectnotify_bysrcname(const char* szSrcName, const char* szObject)
{
    CSyncThread::getSyncEngine().getNotify().addObjectNotify(szSrcName, szObject);
}

void rho_sync_cleanobjectnotify()
{
    CSyncThread::getSyncEngine().getNotify().cleanObjectNotifications();
}

int rho_sync_get_lastsync_objectcount(int nSrcID)
{
    return CSyncThread::getSyncEngine().getNotify().getLastSyncObjectCount(nSrcID);
}

int rho_sync_get_pagesize()
{
    return CSyncThread::getSyncEngine().getSyncPageSize();
}

void rho_sync_set_pagesize(int nPageSize)
{
    return CSyncThread::getSyncEngine().setSyncPageSize(nPageSize);
}

void rho_sync_set_threaded_mode(int b)
{
    return CSyncThread::getSyncEngine().setNonThreadedMode(b==0);
}

}
<commit_msg>fix mspec<commit_after>#include "SyncThread.h"
#include "common/RhoTime.h"
#include "common/RhoConf.h"
#include "common/RhoFilePath.h"

#include "ruby/ext/rho/rhoruby.h"

namespace rho {
namespace sync {

using namespace rho::common;
using namespace rho::db;

IMPLEMENT_LOGCLASS(CSyncThread,"Sync");
CSyncThread* CSyncThread::m_pInstance = 0;

/*static*/ CSyncThread* CSyncThread::Create(common::IRhoClassFactory* factory)
{
    if ( m_pInstance )
        return m_pInstance;

    m_pInstance = new CSyncThread(factory);
    return m_pInstance;
}

/*static*/void CSyncThread::Destroy()
{
    if ( m_pInstance )
        delete m_pInstance;

    m_pInstance = 0;
}

CSyncThread::CSyncThread(common::IRhoClassFactory* factory) : CThreadQueue(factory)
{
    CThreadQueue::setLogCategory(getLogCategory());

    if( RHOCONF().isExist("sync_poll_interval") )
        setPollInterval(RHOCONF().getInt("sync_poll_interval"));

    m_oSyncEngine.setFactory(factory);

    if ( RHOCONF().getString("syncserver").length() > 0 )
        start(epLow);
}

CSyncThread::~CSyncThread(void)
{
    m_oSyncEngine.exitSync();
    stop(SYNC_WAIT_BEFOREKILL_SECONDS);

    db::CDBAdapter::closeAll();

    LOG(INFO) + "Sync engine thread shutdown";
}

int CSyncThread::getLastPollInterval()
{
    uint64 nowTime = CLocalTime().toULong();

    DBResult( res, CDBAdapter::getUserDB().executeSQL("SELECT last_updated from sources") );
    uint64 latestTimeUpdated = 0;
    for ( ; !res.isEnd(); res.next() )
    {
        uint64 timeUpdated = res.getUInt64ByIdx(0);
        if ( latestTimeUpdated < timeUpdated )
        	latestTimeUpdated = timeUpdated;
    }

	return latestTimeUpdated > 0 ? (int)(nowTime-latestTimeUpdated) : 0;
}

void CSyncThread::processCommands()//throws Exception
{
    if ( isNoCommands() )
        addQueueCommand(new CSyncCommand(scNone,false));

    CThreadQueue::processCommands();
}

void CSyncThread::checkShowStatus(CSyncCommand& oSyncCmd)
{
	boolean bShowStatus = oSyncCmd.m_bShowStatus;
	m_oSyncEngine.getNotify().enableReporting(bShowStatus);
	//if (bShowStatus)
		//m_statusListener.createStatusPopup(RhoRuby.getMessageText("syncronizing_data"));
}

void CSyncThread::processCommand(CQueueCommand* pCmd)
{
    CSyncCommand& oSyncCmd = *((CSyncCommand*)pCmd);
    switch(oSyncCmd.m_nCmdCode)
    {
    case scNone:
        if ( getPollInterval() )
        {
            checkShowStatus(oSyncCmd);
            m_oSyncEngine.doSyncAllSources();
        }
        break;
    case scSyncAll:
        checkShowStatus(oSyncCmd);
        m_oSyncEngine.doSyncAllSources();
        break;
    case scSyncOne:
        {
			checkShowStatus(oSyncCmd);
            m_oSyncEngine.doSyncSource(CSyncEngine::CSourceID(oSyncCmd.m_nCmdParam,oSyncCmd.m_strCmdParam));
        }
        break;
    case scSearchOne:
        {
			checkShowStatus(oSyncCmd);
            m_oSyncEngine.doSearch( ((CSyncSearchCommand&)oSyncCmd).m_arSources, oSyncCmd.m_strCmdParam,
                ((CSyncSearchCommand&)oSyncCmd).m_strFrom, ((CSyncSearchCommand&)oSyncCmd).m_bSyncChanges,
                oSyncCmd.m_nCmdParam);
        }
        break;
    case scLogin:
    	{
    		CSyncLoginCommand& oLoginCmd = (CSyncLoginCommand&)oSyncCmd;

            checkShowStatus(oSyncCmd);
    		m_oSyncEngine.login(oLoginCmd.m_strName, oLoginCmd.m_strPassword, oLoginCmd.m_strCmdParam );
    	}
        break;
    }
}

void CSyncThread::setPollInterval(int nInterval)
{
    if ( nInterval == 0 )
        m_oSyncEngine.stopSync();

    CThreadQueue::setPollInterval(nInterval);
}

};
};

extern "C" {

using namespace rho::sync;
using namespace rho::db;
void rho_sync_destroy()
{
	CSyncThread::Destroy();
}

void rho_sync_doSyncAllSources(int show_status_popup)
{
    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncCommand(CSyncThread::scSyncAll,show_status_popup!=0));
    //rho_sync_doSyncSourceByUrl("http://dev.rhosync.rhohub.com/apps/SugarCRM/sources/SugarAccounts");
}

void rho_sync_doSyncSource(unsigned long nSrcID,int show_status_popup)
{
    CRhoRubyStringOrInt oSrcID = rho_ruby_getstringorint(nSrcID);
    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncCommand(CSyncThread::scSyncOne, oSrcID.m_szStr, (int)oSrcID.m_nInt, show_status_popup!=0 ) );
}

void rho_sync_stop()
{
	if (CSyncThread::getSyncEngine().isSyncing() )
	{
		CSyncThread::getSyncEngine().stopSyncByUser();
        CSyncThread::getInstance()->stopWait();

        while( CDBAdapter::isAnyInsideTransaction() )
			CSyncThread::getInstance()->sleep(100);
	}
}

extern "C" void
source_iter(const char* szName, void* parSources)
{
    rho::Vector<rho::String>& arSources = *((rho::Vector<rho::String>*)(parSources));
    arSources.addElement(szName);
}

void rho_sync_doSearch(unsigned long ar_sources, const char *from, const char *params, bool sync_changes, int nProgressStep,
    const char* callback, const char* callback_params)
{
    rho_sync_stop();
    if ( callback && *callback )
        CSyncThread::getSyncEngine().getNotify().setSearchNotification( callback, callback_params ? callback_params : "");

    rho::Vector<rho::String> arSources;
    rho_ruby_enum_strary(ar_sources, source_iter, &arSources);

    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncSearchCommand(from,params,arSources,sync_changes,nProgressStep) );
}

void rho_sync_doSyncSourceByUrl(const char* szSrcUrl)
{
    const char* szLastSlash = strrchr(szSrcUrl, '\\');
    if ( !szLastSlash )
        szLastSlash = strrchr(szSrcUrl, '/');

    const char* szQuest = strrchr(szSrcUrl, '?');

    rho::String strName = "";
    if (szQuest && szLastSlash)
        strName = rho::String(szLastSlash+1, szQuest-szLastSlash-1);
    else
        strName = szLastSlash ? szLastSlash + 1 : szSrcUrl;

    //TODO: save query params
    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncCommand(CSyncThread::scSyncOne, strName, (int)0, false ) );
}

void rho_sync_set_pollinterval(int nInterval)
{
    CSyncThread::getInstance()->setPollInterval(nInterval);
}

void rho_sync_set_syncserver(char* syncserver)
{
    rho_sync_stop();

	CSyncThread::getSyncEngine().setSyncServer(syncserver);

    if ( syncserver && *syncserver )
        CSyncThread::getInstance()->start(CSyncThread::epLow);
    else
        CSyncThread::getInstance()->stop(CSyncThread::SYNC_WAIT_BEFOREKILL_SECONDS);
}

void rho_sync_login(const char *name, const char *password, const char* callback)
{
    rho_sync_stop();
    CSyncThread::getInstance()->addQueueCommand(new CSyncThread::CSyncLoginCommand(name, password, callback) );
}

int rho_sync_logged_in()
{
	CDBAdapter& db = CDBAdapter::getUserDB();
    return CSyncThread::getSyncEngine().isLoggedIn() ? 1 : 0;
}

void rho_sync_logout()
{
    rho_sync_stop();

	CDBAdapter& db = CDBAdapter::getUserDB();
    CSyncThread::getSyncEngine().logout();
}

void rho_sync_set_notification(int source_id, const char *url, char* params)
{
    return CSyncThread::getSyncEngine().getNotify().setSyncNotification(source_id, url, params ? params : "");
}

void rho_sync_clear_notification(int source_id)
{
    return CSyncThread::getSyncEngine().getNotify().clearSyncNotification(source_id);
}

void rho_sync_set_bulk_notification(const char *url, char* params)
{
    return CSyncThread::getSyncEngine().getNotify().setBulkSyncNotification(url, params ? params : "");
}

void rho_sync_clear_bulk_notification()
{
    return CSyncThread::getSyncEngine().getNotify().clearBulkSyncNotification();
}

unsigned long rho_sync_get_attrs(const char* szPartition, int nSrcID)
{
    return (VALUE)CDBAdapter::getDB(szPartition).getAttrMgr().getAttrsBySrc(nSrcID);
}

unsigned long rho_sync_is_blob_attr(const char* szPartition, int nSrcID, const char* szAttrName)
{
    return rho_ruby_create_boolean( CDBAdapter::getDB(szPartition).getAttrMgr().isBlobAttr(nSrcID, szAttrName) );
}

void rho_sync_setobjectnotify_url(const char* szUrl)
{
    CSyncNotify::setObjectNotifyUrl(szUrl);
}

void rho_sync_addobjectnotify(int nSrcID, const char* szObject)
{
    CSyncThread::getSyncEngine().getNotify().addObjectNotify(nSrcID, szObject);
}

void rho_sync_addobjectnotify_bysrcname(const char* szSrcName, const char* szObject)
{
    CSyncThread::getSyncEngine().getNotify().addObjectNotify(szSrcName, szObject);
}

void rho_sync_cleanobjectnotify()
{
    CSyncThread::getSyncEngine().getNotify().cleanObjectNotifications();
}

int rho_sync_get_lastsync_objectcount(int nSrcID)
{
    return CSyncThread::getSyncEngine().getNotify().getLastSyncObjectCount(nSrcID);
}

int rho_sync_get_pagesize()
{
    return CSyncThread::getSyncEngine().getSyncPageSize();
}

void rho_sync_set_pagesize(int nPageSize)
{
    CSyncThread::getSyncEngine().setSyncPageSize(nPageSize);
}

void rho_sync_set_threaded_mode(int b)
{
    CSyncThread::getInstance()->setNonThreadedMode(b==0);
    CSyncThread::getSyncEngine().setNonThreadedMode(b==0);
}

}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief upload request handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "RestUploadHandler.h"

#include "Basics/FileUtils.h"
#include "BasicsC/files.h"
#include "Logger/Logger.h"
#include "HttpServer/HttpServer.h"
#include "Rest/HttpRequest.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::RestUploadHandler (HttpRequest* request)
  : RestVocbaseBaseHandler(request) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::~RestUploadHandler () {
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                   Handler methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Handler::status_e RestUploadHandler::execute() {
  // extract the request type
  const HttpRequest::HttpRequestType type = _request->requestType();

  if (type != HttpRequest::HTTP_REQUEST_POST) {
    generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);

    return Handler::HANDLER_DONE;
  }

  char* filename = NULL;

  if (TRI_GetTempName("uploads", &filename, true) != TRI_ERROR_NO_ERROR) {
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not generate temp file");
    return Handler::HANDLER_FAILED;
  }

  char* relative = TRI_GetFilename(filename);
  TRI_Free(TRI_CORE_MEM_ZONE, filename);

  try {
    FileUtils::spit(string(filename), _request->body(), _request->bodySize());
  }
  catch (...) {
    TRI_Free(TRI_CORE_MEM_ZONE, relative);
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
    return Handler::HANDLER_FAILED;
  }

  char* fullName = TRI_Concatenate2File("uploads", relative);
  TRI_Free(TRI_CORE_MEM_ZONE, relative);

  // create the response
  _response = createResponse(HttpResponse::CREATED);
  _response->setContentType("application/json; charset=utf-8");

  TRI_json_t json;

  TRI_InitArrayJson(TRI_CORE_MEM_ZONE, &json);
  TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, &json, "filename", TRI_CreateStringJson(TRI_CORE_MEM_ZONE, fullName));

  generateResult(HttpResponse::CREATED, &json);
  TRI_DestroyJson(TRI_CORE_MEM_ZONE, &json);

  // success
  return Handler::HANDLER_DONE;
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>fix temp file creation on Windows<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief upload request handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "RestUploadHandler.h"

#include "Basics/FileUtils.h"
#include "BasicsC/files.h"
#include "Logger/Logger.h"
#include "HttpServer/HttpServer.h"
#include "Rest/HttpRequest.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::RestUploadHandler (HttpRequest* request)
  : RestVocbaseBaseHandler(request) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::~RestUploadHandler () {
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                   Handler methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Handler::status_e RestUploadHandler::execute() {
  // extract the request type
  const HttpRequest::HttpRequestType type = _request->requestType();

  if (type != HttpRequest::HTTP_REQUEST_POST) {
    generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);

    return Handler::HANDLER_DONE;
  }

  char* filename = NULL;

  if (TRI_GetTempName("uploads", &filename, false) != TRI_ERROR_NO_ERROR) {
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not generate temp file");
    return Handler::HANDLER_FAILED;
  }

  char* relative = TRI_GetFilename(filename);
  TRI_Free(TRI_CORE_MEM_ZONE, filename);

  LOGGER_TRACE("saving uploaded file of length " << _request->bodySize() <<
               " in file '" << filename << "', relative '" << relative << "'");

  try {
    FileUtils::spit(string(filename), _request->body(), _request->bodySize());
  }
  catch (...) {
    TRI_Free(TRI_CORE_MEM_ZONE, relative);
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
    return Handler::HANDLER_FAILED;
  }

  char* fullName = TRI_Concatenate2File("uploads", relative);
  TRI_Free(TRI_CORE_MEM_ZONE, relative);

  // create the response
  _response = createResponse(HttpResponse::CREATED);
  _response->setContentType("application/json; charset=utf-8");

  TRI_json_t json;

  TRI_InitArrayJson(TRI_CORE_MEM_ZONE, &json);
  TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, &json, "filename", TRI_CreateStringJson(TRI_CORE_MEM_ZONE, fullName));

  generateResult(HttpResponse::CREATED, &json);
  TRI_DestroyJson(TRI_CORE_MEM_ZONE, &json);

  // success
  return Handler::HANDLER_DONE;
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief upload request handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "RestUploadHandler.h"

#include "Basics/FileUtils.h"
#include "Basics/files.h"
#include "Basics/logging.h"
#include "Basics/StringUtils.h"
#include "HttpServer/HttpServer.h"
#include "Rest/HttpRequest.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::RestUploadHandler (HttpRequest* request)
  : RestVocbaseBaseHandler(request) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::~RestUploadHandler () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   Handler methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Handler::status_t RestUploadHandler::execute () {
  // extract the request type
  const HttpRequest::HttpRequestType type = _request->requestType();

  if (type != HttpRequest::HTTP_REQUEST_POST) {
    generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);

    return status_t(Handler::HANDLER_DONE);
  }

  char* filename = nullptr;

  if (TRI_GetTempName("uploads", &filename, false) != TRI_ERROR_NO_ERROR) {
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not generate temp file");
    return status_t(Handler::HANDLER_FAILED);
  }

  char* relative = TRI_GetFilename(filename);

  LOG_TRACE("saving uploaded file of length %llu in file '%s', relative '%s'",
            (unsigned long long) _request->bodySize(),
            filename,
            relative);

  char const* body = _request->body();
  size_t bodySize  = _request->bodySize();

  bool found;
  char const* value = _request->value("multipart", found);
  bool multiPart = false;

  if (found) {
    multiPart = triagens::basics::StringUtils::boolean(value);

    if (multiPart) {
      if (! parseMultiPart(body, bodySize)) {
        TRI_Free(TRI_CORE_MEM_ZONE, relative);
        TRI_Free(TRI_CORE_MEM_ZONE, filename);
        generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "invalid multipart request");
        return status_t(Handler::HANDLER_FAILED);
      }
    }
  }

  try {
    FileUtils::spit(string(filename), body, bodySize);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
  }
  catch (...) {
    TRI_Free(TRI_CORE_MEM_ZONE, relative);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
    return status_t(Handler::HANDLER_FAILED);
  }

  char* fullName = TRI_Concatenate2File("uploads", relative);
  TRI_Free(TRI_CORE_MEM_ZONE, relative);

  // create the response
  _response = createResponse(HttpResponse::CREATED);
  _response->setContentType("application/json; charset=utf-8");

  TRI_json_t json;

  TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &json);
  TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, &json, "filename", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, fullName, strlen(fullName)));

  generateResult(HttpResponse::CREATED, &json);
  TRI_DestroyJson(TRI_UNKNOWN_MEM_ZONE, &json);

  // success
  return status_t(Handler::HANDLER_DONE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief parses a multi-part request body and determines the boundaries of
/// its first element
////////////////////////////////////////////////////////////////////////////////

bool RestUploadHandler::parseMultiPart (char const*& body,
                                        size_t& length) {
  char const* beg = _request->body();
  char const* end = beg + _request->bodySize();

  while (beg < end && (*beg == '\r' || *beg == '\n' || *beg == ' ')) {
    ++beg;
  }

  // find delimiter
  char const* ptr = beg;
  while (ptr < end && *ptr == '-') {
    ++ptr;
  }

  while (ptr < end && *ptr != '\r' && *ptr != '\n') {
    ++ptr;
  }
  if (ptr == beg) {
    // oops
    return false;
  }

  std::string const delimiter(beg, ptr - beg);
  if (ptr < end && *ptr == '\r') {
    ++ptr;
  }
  if (ptr < end && *ptr == '\n') {
    ++ptr;
  }

  std::vector<std::pair<char const*, size_t>> parts;

  while (ptr < end) {
    char const* p = TRI_IsContainedMemory(ptr, end - ptr, delimiter.c_str(), delimiter.size());
    if (p == nullptr || p + delimiter.size() + 2 >= end || p - 2 <= ptr) {
      return false;
    }

    char const* q = p;
    if (*(q - 1) == '\n') {
      --q;
    }
    if (*(q - 1) == '\r') {
      --q;
    }

    parts.push_back(std::make_pair(ptr, q - ptr));
    ptr = p + delimiter.size();
    if (*ptr == '-' && *(ptr + 1) == '-') {
      // eom
      break;
    }
    if (*ptr == '\r') {
      ++ptr;
    }
    if (ptr < end && *ptr == '\n') {
      ++ptr;
    }
  }

  for (auto& part : parts) {
    auto ptr = part.first;
    auto end = part.first + part.second;
    char const* data = nullptr;

    while (ptr < end) {
      while (ptr < end && *ptr == ' ') {
        ++ptr;
      }
      if (ptr < end && (*ptr == '\r' || *ptr == '\n')) {
        // end of headers
        if (*ptr == '\r') {
          ++ptr;
        }
        if (ptr < end && *ptr == '\n') {
          ++ptr;
        }
        data = ptr;
        break;
      }

      // header line
      char const* eol = TRI_IsContainedMemory(ptr, end - ptr, "\r\n", 2);

      if (eol == nullptr) {
        eol = TRI_IsContainedMemory(ptr, end - ptr, "\n", 1);
      }

      if (eol == nullptr) {
        return false;
      }

      char const* colon = TRI_IsContainedMemory(ptr, end - ptr, ":", 1);
      if (colon == nullptr) {
        return false;
      }

      char const* p = colon;
      while (p > ptr && *(p - 1) == ' ') {
        --p;
      }

      ++colon;
      while (colon < eol && *colon == ' ') {
        ++colon;
      }

      char const* q = eol;
      while (q > ptr && *(q - 1) == ' ') {
        --q;
      }

      ptr = eol;
      if (*ptr == '\r') {
        ++ptr;
      }
      if (ptr < end && *ptr == '\n') {
        ++ptr;
      }
    }

    if (data == nullptr) {
      return false;
    }

    body = data;
    length = static_cast<size_t>(end - data);

    // stop after the first found element
    break;
  }

  return true;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>fixed leak<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief upload request handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "RestUploadHandler.h"

#include "Basics/FileUtils.h"
#include "Basics/files.h"
#include "Basics/logging.h"
#include "Basics/StringUtils.h"
#include "HttpServer/HttpServer.h"
#include "Rest/HttpRequest.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::RestUploadHandler (HttpRequest* request)
  : RestVocbaseBaseHandler(request) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::~RestUploadHandler () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   Handler methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Handler::status_t RestUploadHandler::execute () {
  // extract the request type
  const HttpRequest::HttpRequestType type = _request->requestType();

  if (type != HttpRequest::HTTP_REQUEST_POST) {
    generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);

    return status_t(Handler::HANDLER_DONE);
  }

  char* filename = nullptr;

  if (TRI_GetTempName("uploads", &filename, false) != TRI_ERROR_NO_ERROR) {
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not generate temp file");
    return status_t(Handler::HANDLER_FAILED);
  }

  char* relative = TRI_GetFilename(filename);

  LOG_TRACE("saving uploaded file of length %llu in file '%s', relative '%s'",
            (unsigned long long) _request->bodySize(),
            filename,
            relative);

  char const* body = _request->body();
  size_t bodySize  = _request->bodySize();

  bool found;
  char const* value = _request->value("multipart", found);
  bool multiPart = false;

  if (found) {
    multiPart = triagens::basics::StringUtils::boolean(value);

    if (multiPart) {
      if (! parseMultiPart(body, bodySize)) {
        TRI_Free(TRI_CORE_MEM_ZONE, relative);
        TRI_Free(TRI_CORE_MEM_ZONE, filename);
        generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "invalid multipart request");
        return status_t(Handler::HANDLER_FAILED);
      }
    }
  }

  try {
    FileUtils::spit(string(filename), body, bodySize);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
  }
  catch (...) {
    TRI_Free(TRI_CORE_MEM_ZONE, relative);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
    return status_t(Handler::HANDLER_FAILED);
  }

  char* fullName = TRI_Concatenate2File("uploads", relative);
  TRI_Free(TRI_CORE_MEM_ZONE, relative);

  // create the response
  _response = createResponse(HttpResponse::CREATED);
  _response->setContentType("application/json; charset=utf-8");

  TRI_json_t json;

  TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &json);
  TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, &json, "filename", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, fullName, strlen(fullName)));
  TRI_Free(TRI_CORE_MEM_ZONE, filename);

  generateResult(HttpResponse::CREATED, &json);
  TRI_DestroyJson(TRI_UNKNOWN_MEM_ZONE, &json);

  // success
  return status_t(Handler::HANDLER_DONE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief parses a multi-part request body and determines the boundaries of
/// its first element
////////////////////////////////////////////////////////////////////////////////

bool RestUploadHandler::parseMultiPart (char const*& body,
                                        size_t& length) {
  char const* beg = _request->body();
  char const* end = beg + _request->bodySize();

  while (beg < end && (*beg == '\r' || *beg == '\n' || *beg == ' ')) {
    ++beg;
  }

  // find delimiter
  char const* ptr = beg;
  while (ptr < end && *ptr == '-') {
    ++ptr;
  }

  while (ptr < end && *ptr != '\r' && *ptr != '\n') {
    ++ptr;
  }
  if (ptr == beg) {
    // oops
    return false;
  }

  std::string const delimiter(beg, ptr - beg);
  if (ptr < end && *ptr == '\r') {
    ++ptr;
  }
  if (ptr < end && *ptr == '\n') {
    ++ptr;
  }

  std::vector<std::pair<char const*, size_t>> parts;

  while (ptr < end) {
    char const* p = TRI_IsContainedMemory(ptr, end - ptr, delimiter.c_str(), delimiter.size());
    if (p == nullptr || p + delimiter.size() + 2 >= end || p - 2 <= ptr) {
      return false;
    }

    char const* q = p;
    if (*(q - 1) == '\n') {
      --q;
    }
    if (*(q - 1) == '\r') {
      --q;
    }

    parts.push_back(std::make_pair(ptr, q - ptr));
    ptr = p + delimiter.size();
    if (*ptr == '-' && *(ptr + 1) == '-') {
      // eom
      break;
    }
    if (*ptr == '\r') {
      ++ptr;
    }
    if (ptr < end && *ptr == '\n') {
      ++ptr;
    }
  }

  for (auto& part : parts) {
    auto ptr = part.first;
    auto end = part.first + part.second;
    char const* data = nullptr;

    while (ptr < end) {
      while (ptr < end && *ptr == ' ') {
        ++ptr;
      }
      if (ptr < end && (*ptr == '\r' || *ptr == '\n')) {
        // end of headers
        if (*ptr == '\r') {
          ++ptr;
        }
        if (ptr < end && *ptr == '\n') {
          ++ptr;
        }
        data = ptr;
        break;
      }

      // header line
      char const* eol = TRI_IsContainedMemory(ptr, end - ptr, "\r\n", 2);

      if (eol == nullptr) {
        eol = TRI_IsContainedMemory(ptr, end - ptr, "\n", 1);
      }

      if (eol == nullptr) {
        return false;
      }

      char const* colon = TRI_IsContainedMemory(ptr, end - ptr, ":", 1);
      if (colon == nullptr) {
        return false;
      }

      char const* p = colon;
      while (p > ptr && *(p - 1) == ' ') {
        --p;
      }

      ++colon;
      while (colon < eol && *colon == ' ') {
        ++colon;
      }

      char const* q = eol;
      while (q > ptr && *(q - 1) == ' ') {
        --q;
      }

      ptr = eol;
      if (*ptr == '\r') {
        ++ptr;
      }
      if (ptr < end && *ptr == '\n') {
        ++ptr;
      }
    }

    if (data == nullptr) {
      return false;
    }

    body = data;
    length = static_cast<size_t>(end - data);

    // stop after the first found element
    break;
  }

  return true;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    MathTools.cpp
  \author    Jens Krueger
        SCI Institute
        University of Utah
  \version  1.11
  \date    October 2008
*/

#include "MathTools.h"
#include <algorithm>

UINT32 MathTools::Log(UINT32 value, UINT32 base) {
  return UINT32(log(float(value)) / log(float(base)));
}

float MathTools::Log(float value, float base) {
  return log(value) / log(base);
}

UINT32 MathTools::Pow(UINT32 base, UINT32 exponent) {
  return UINT32(0.5f+pow(float(base), float(exponent)));
}

UINT64 MathTools::Pow(UINT64 base, UINT64 exponent) {
  return UINT64(0.5+pow(double(base), double(exponent)));
}

UINT32 MathTools::Log2(UINT32 n) {
  int iLog=0;
  while( n>>=1 ) iLog++;
  return iLog;
}

UINT32 MathTools::Pow2(UINT32 e) {
  return 1<<e;
}

UINT64 MathTools::Log2(UINT64 n) {
  int iLog=0;
  while( n>>=1 ) iLog++;
  return iLog;
}

UINT64 MathTools::Pow2(UINT64 e) {
  return static_cast<UINT64>(1) << e;
}

UINT32 MathTools::GaussianSum(UINT32 n) {
  return n*(n+1)/2;
}

bool MathTools::IsPow2(UINT32 n) {
    return ((n&(n-1))==0);
};

UINT32 MathTools::NextPow2(UINT32 n, bool bReturn_ID_on_Pow2) {
    if (bReturn_ID_on_Pow2 && IsPow2(n)) return n;
    return Pow2(Log2(n)+1);
}

bool MathTools::NaN(float f)
{
#ifdef USABLE_TR1
  return std::tr1::isnan(f);
#elif defined(_MSC_VER)
  return _finite(f);
#else
  // Hack, relies on 'f' being IEEE-754!
  return f != f;
#endif
}

float MathTools::Clamp(float val, float a, float b) {
  return std::max(a, std::min(b, val));
}

UINT32 MathTools::Clamp(UINT32 val, UINT32 a, UINT32 b) {
  return std::max(a, std::min(b, val));
}

UINT64 MathTools::Clamp(UINT64 val, UINT64 a, UINT64 b) {
  return std::max(a, std::min(b, val));
}

int MathTools::Clamp(int val, int a, int b) {
  return std::max(a, std::min(b, val));
}
<commit_msg>fixed performance warning on MS compiler<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    MathTools.cpp
  \author    Jens Krueger
        SCI Institute
        University of Utah
  \version  1.11
  \date    October 2008
*/

#include "MathTools.h"
#include <algorithm>

UINT32 MathTools::Log(UINT32 value, UINT32 base) {
  return UINT32(log(float(value)) / log(float(base)));
}

float MathTools::Log(float value, float base) {
  return log(value) / log(base);
}

UINT32 MathTools::Pow(UINT32 base, UINT32 exponent) {
  return UINT32(0.5f+pow(float(base), float(exponent)));
}

UINT64 MathTools::Pow(UINT64 base, UINT64 exponent) {
  return UINT64(0.5+pow(double(base), double(exponent)));
}

UINT32 MathTools::Log2(UINT32 n) {
  int iLog=0;
  while( n>>=1 ) iLog++;
  return iLog;
}

UINT32 MathTools::Pow2(UINT32 e) {
  return 1<<e;
}

UINT64 MathTools::Log2(UINT64 n) {
  int iLog=0;
  while( n>>=1 ) iLog++;
  return iLog;
}

UINT64 MathTools::Pow2(UINT64 e) {
  return static_cast<UINT64>(1) << e;
}

UINT32 MathTools::GaussianSum(UINT32 n) {
  return n*(n+1)/2;
}

bool MathTools::IsPow2(UINT32 n) {
    return ((n&(n-1))==0);
};

UINT32 MathTools::NextPow2(UINT32 n, bool bReturn_ID_on_Pow2) {
    if (bReturn_ID_on_Pow2 && IsPow2(n)) return n;
    return Pow2(Log2(n)+1);
}

bool MathTools::NaN(float f)
{
#ifdef USABLE_TR1
  return std::tr1::isnan(f);
#elif defined(_MSC_VER)
  return _finite(f) != 0;
#else
  // Hack, relies on 'f' being IEEE-754!
  return f != f;
#endif
}

float MathTools::Clamp(float val, float a, float b) {
  return std::max(a, std::min(b, val));
}

UINT32 MathTools::Clamp(UINT32 val, UINT32 a, UINT32 b) {
  return std::max(a, std::min(b, val));
}

UINT64 MathTools::Clamp(UINT64 val, UINT64 a, UINT64 b) {
  return std::max(a, std::min(b, val));
}

int MathTools::Clamp(int val, int a, int b) {
  return std::max(a, std::min(b, val));
}
<|endoftext|>


<commit_before>/*******************************************************************************
* Copyright 2009-2015 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

#include "fx/ConvolverSound.h"
#include "fx/BinauralSound.h"
#include "fx/Source.h"
#include "fx/HRTFLoader.h"
#include "util/ThreadPool.h"
#include "devices/DeviceManager.h"
#include "devices/IDevice.h"
#include "devices/IDeviceFactory.h"
#include "devices/IHandle.h"
#include "plugin/PluginManager.h"
#include "file/File.h"
#include "respec/ChannelMapper.h"
#include "respec/JOSResample.h"
#include "Exception.h"

#include <windows.h>
#include <string>
#include <iostream>
#include <thread>
#include <chrono>

using namespace aud;

int main(int argc, char* argv[])
{
	/*This demo uses KEMAR HRTFs.*/
	if(argc != 3 && argc != 4)
	{
		std::cerr << "Usage: " << argv[0] << " <sound>"  << " <HRTFs path>" << " [inverse speaker impulse response]" << std::endl;
		return 1;
	}

	PluginManager::loadPlugins("");

	auto factory = DeviceManager::getDefaultDeviceFactory();
	auto device = factory->openDevice();

	std::shared_ptr<FFTPlan> plan(std::make_shared<FFTPlan>(4096, true));
	std::shared_ptr<ThreadPool> threadPool(std::make_shared<ThreadPool>(std::thread::hardware_concurrency()));
	std::shared_ptr<Source> source = std::make_shared<Source>(0, 0);
	std::shared_ptr<HRTF> hrtfs;
	try
	{
		hrtfs = HRTFLoader::loadRightHRTFs(plan, ".wav", argv[2]);
	}
	catch (Exception& e)
	{
		std::cerr << "Error loading hrtfs - " << e.getMessage() << std::endl;
		return 2;
	}

	DeviceSpecs specs;
	specs.channels = CHANNELS_MONO;
	specs.rate = hrtfs->getSpecs().rate;
	std::shared_ptr<JOSResample> sound(std::make_shared<JOSResample>(std::make_shared<ChannelMapper>(std::make_shared<File>(argv[1]), specs), specs));

	std::shared_ptr<BinauralSound> binaural(std::make_shared<BinauralSound>(sound, hrtfs, source, threadPool, plan));

	device->lock();
	if (argc == 4)
	{
		std::shared_ptr<ImpulseResponse> ir(std::make_shared<ImpulseResponse>(std::make_shared<StreamBuffer>(std::make_shared<File>(argv[3])), plan));
		std::shared_ptr<ConvolverSound> convolver = std::make_shared<ConvolverSound>(binaural, ir, threadPool, plan);
		auto handle = device->play(convolver);
		handle->setLoopCount(-1);
	}
	else
	{
		auto handle = device->play(binaural);
		handle->setLoopCount(-1);
	}
	device->unlock();

	float x = 0;
	float y = 0;
	float yInc = 5;
	while(true)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(500));
		x += 15;
		y += yInc;
		if(y >= 60)
		{
			y = 60;
			yInc = -5;
		}
		else if(y <= -40)
		{
			y = -40;
			yInc = 5;
		}
		if(x >= 360)
			x = 0;

		source->setAzimuth(x);
		source->setElevation(y);
		std::cout << " Azimuth: " << x << " - Elevation: " << y << std::endl;
	}

	return 0;
}
<commit_msg>Removed unnecessary header from the binaural demo.<commit_after>/*******************************************************************************
* Copyright 2009-2015 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

#include "fx/ConvolverSound.h"
#include "fx/BinauralSound.h"
#include "fx/Source.h"
#include "fx/HRTFLoader.h"
#include "util/ThreadPool.h"
#include "devices/DeviceManager.h"
#include "devices/IDevice.h"
#include "devices/IDeviceFactory.h"
#include "devices/IHandle.h"
#include "plugin/PluginManager.h"
#include "file/File.h"
#include "respec/ChannelMapper.h"
#include "respec/JOSResample.h"
#include "Exception.h"

#include <string>
#include <iostream>
#include <thread>
#include <chrono>

using namespace aud;

int main(int argc, char* argv[])
{
	/*This demo uses KEMAR HRTFs.*/
	if(argc != 3 && argc != 4)
	{
		std::cerr << "Usage: " << argv[0] << " <sound>"  << " <HRTFs path>" << " [inverse speaker impulse response]" << std::endl;
		return 1;
	}

	PluginManager::loadPlugins("");

	auto factory = DeviceManager::getDefaultDeviceFactory();
	auto device = factory->openDevice();

	std::shared_ptr<FFTPlan> plan(std::make_shared<FFTPlan>(4096, true));
	std::shared_ptr<ThreadPool> threadPool(std::make_shared<ThreadPool>(std::thread::hardware_concurrency()));
	std::shared_ptr<Source> source = std::make_shared<Source>(0, 0);
	std::shared_ptr<HRTF> hrtfs;
	try
	{
		hrtfs = HRTFLoader::loadRightHRTFs(plan, ".wav", argv[2]);
	}
	catch (Exception& e)
	{
		std::cerr << "Error loading hrtfs - " << e.getMessage() << std::endl;
		return 2;
	}

	DeviceSpecs specs;
	specs.channels = CHANNELS_MONO;
	specs.rate = hrtfs->getSpecs().rate;
	std::shared_ptr<JOSResample> sound(std::make_shared<JOSResample>(std::make_shared<ChannelMapper>(std::make_shared<File>(argv[1]), specs), specs));

	std::shared_ptr<BinauralSound> binaural(std::make_shared<BinauralSound>(sound, hrtfs, source, threadPool, plan));

	device->lock();
	if (argc == 4)
	{
		std::shared_ptr<ImpulseResponse> ir(std::make_shared<ImpulseResponse>(std::make_shared<StreamBuffer>(std::make_shared<File>(argv[3])), plan));
		std::shared_ptr<ConvolverSound> convolver = std::make_shared<ConvolverSound>(binaural, ir, threadPool, plan);
		auto handle = device->play(convolver);
		handle->setLoopCount(-1);
	}
	else
	{
		auto handle = device->play(binaural);
		handle->setLoopCount(-1);
	}
	device->unlock();

	float x = 0;
	float y = 0;
	float yInc = 5;
	while(true)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(500));
		x += 15;
		y += yInc;
		if(y >= 60)
		{
			y = 60;
			yInc = -5;
		}
		else if(y <= -40)
		{
			y = -40;
			yInc = 5;
		}
		if(x >= 360)
			x = 0;

		source->setAzimuth(x);
		source->setElevation(y);
		std::cout << " Azimuth: " << x << " - Elevation: " << y << std::endl;
	}

	return 0;
}
<|endoftext|>


<commit_before>/*
 *  This file is parte of grammargen. A tool to generate sequences of
 *  characters from a given grammar.
 *  Copyright (C) 2015 Raphael Santos, http://www.raphaelss.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <cstdio>
#include <iostream>
#include <stdexcept>
#include <string>
#include "grammar.hpp"

struct op {
  void operator()(char c) {
    std::putchar(c);
  }

  void operator()(const std::string &c) {
    std::fwrite(c.data(), c.size(), 1, stdout);
  }
};

int main(int argc, char **argv) {
  int n;
  if (argc < 3 || argc % 3 != 0 || (n = std::stoi(argv[1])) < 0) {
    std::cerr << "Usage: " << argv[0]
              << " axiom number_of_iterations [rules]\n"
              << "       rule = probability char string\n";
    return 1;
  }
  Grammar g(argv[2]);
  argc -= 3;
  argv += 3;
  double prob;
  while (argc) {
    try {
      prob = std::stod(argv[0]);
    } catch (const std::invalid_argument &e) {
      std::cerr << "grammargen error: "
                << argv[0] << " is not a positive number\n";
      return 1;
    }
    if (prob <= 0) {
      std::cerr << "grammargen error: "
                << argv[0] << " is not a positive number\n";
      return 1;
    }
    g.addRule(argv[1][0], argv[2], prob);
    argc -= 3;
    argv += 3;
  }
  gen_seq<op>(g, n, g.axiom);
  std::cout << std::endl;
  return 0;
}
<commit_msg>use cstdio instead of iostream.<commit_after>/*
 *  This file is parte of grammargen. A tool to generate sequences of
 *  characters from a given grammar.
 *  Copyright (C) 2015 Raphael Santos, http://www.raphaelss.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <cstdio>
#include <stdexcept>
#include <string>
#include "grammar.hpp"

struct op {
  void operator()(char c) {
    std::putchar(c);
  }

  void operator()(const std::string &c) {
    std::fwrite(c.data(), c.size(), sizeof(std::string::value_type), stdout);
  }
};

int main(int argc, char **argv) {
  int n;
  if (argc < 3 || argc % 3 != 0 || (n = std::stoi(argv[1])) < 0) {
    fprintf(stderr, "Usage: %s axiom number_of_iterations [rules]\n"
                    "       rule = probability char string\n", argv[0]);
    return 1;
  }
  Grammar g(argv[2]);
  argc -= 3;
  argv += 3;
  double prob;
  while (argc) {
    try {
      if ((prob = std::stod(argv[0])) <= 0) {
        throw std::invalid_argument("not a positive number");
      }
    } catch (const std::invalid_argument &e) {
      fprintf(stderr, "grammargen error: %s is not a positive number\n",
              argv[0]);
      return 1;
    }
    g.addRule(argv[1][0], argv[2], prob);
    argc -= 3;
    argv += 3;
  }
  gen_seq<op>(g, n, g.axiom);
  putchar('\n');
  return 0;
}
<|endoftext|>


<commit_before>/*

  test1.cpp: figure out how to use libcmm garbage collection.

 */

//#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>

#include "cmm.h"

#include <vector>
using std::vector;

typedef struct tree_node Tree;
struct tree_node {
    Tree * left, * right;
    void * key;
    int size;   /* maintained to be the number of nodes rooted here */
};

typedef vector<Tree*> tree_v;
typedef tree_v::iterator tree_vit;

/* clear and mark function for libcmm */
static void clear_tree(Tree *t)
{
  //  printf("clear_tree() called! at %p\n",t);
    t->left = NULL;
    t->right = NULL;
    t->key = NULL;
}

static void mark_tree(Tree *t)
{
  //  printf("mark_tree() called! at %p\n",t);
    CMM_MARK(t->left);
    CMM_MARK(t->right);
    CMM_MARK(t->key);
}

mt_t mt_tree = mt_undefined;

#define MBYTE (1<<20)

/* typedef bool finalize_func_t(void *); */
/* global counter of number of finalizers run */
int nfinal = 0;

bool tree_finalizer(void* p) {
#if 0
  char buf[500];
  sprintf(buf,"/home/jaten/dj/strongref/libcmm/finalizer.log.number_%d.pid_%d__and_ppid_%d.tid_%ld",nfinal,getpid(),getppid(),syscall(SYS_gettid));
  FILE* finallog = fopen(buf,"w");
  fprintf(finallog,"%d time in tree_finalizer, now for object %p\n",nfinal++,p);
  fclose(finallog);
  sync();
#endif
  return true;
}

void fill_tree_vector(tree_v& v, int reps) {
  d();
  CMM_ENTER; // expands to:  void **__cmm_stack_pointer = _cmm_begin_anchored()
  for (int n = 0; n < reps; n++) {
       d();
       // allocate and discard all these lines
       Tree* root = (Tree*)cmm_alloc(mt_tree);
       // CMM_ANCHOR(root) won't protect them, b/c no root points to them, so they all get collected upon CMM_EXIT.
       // So instead we'll try to make them all roots:
       cmm_root(root); // don't use CMM_ROOT, because that takes the address of its argument!
       v.push_back(root);
  }
  d();
  CMM_EXIT; // expands to: _cmm_end_anchored(__cmm_stack_pointer)
  d();
}

int main(int argc, char **argv)
{
  if (argc < 2) {
    fprintf(stderr,"supply number of trees to allocate and forget as the only argument to test1.\n");
    exit(1);
  }
  int reps = atoi(argv[1]);

  /* maually test that finalizer works */
  tree_finalizer(0);

    int   n = 0;
    Tree* root = 0;

    FILE* flog = fopen("test1-gc-test.log","w");

    int nbytes = 4096;
    int npages = nbytes / 4096;
    npages=1;

    cmm_init(npages, 0, flog); /* request memory in terms of npages, not nbytes */
    d();
    cmm_debug(true); /* jea debug add */

    mt_tree = CMM_REGTYPE("tree", 1024, clear_tree, mark_tree, tree_finalizer);

    n =0;

    char* msg0 = strdup(cmm_info(3));
    printf("prior to any allocation -- mem_info(3): '%s'\n", msg0);

    tree_v v;

    // call subroutine
    d();
    fill_tree_vector(v,reps);
    d();

    printf("Just allocated 100 Trees in a subroutine, protecting them with CMM_ANCHOR().\n");

    int i = 0;
    for(tree_vit it = v.begin(); it != v.end(); ++it, ++i ) {
      printf("   v[%d] = Tree at address %p\n", i, *it);
    }

    char* msg1 = strdup(cmm_info(3));
    printf("before cmm_collect_now() and cmm_idle()-- mem_info(3): '%s'\n", msg1);

    root = 0;

    d();
    cmm_collect_now();

       /* Unfortunately on the cmm_collect_now() call, we are seeing:

   Just allocated 100 Trees in a subroutine, protecting them with CMM_ANCHOR().
   v[0] = Tree at address 0x10a6000
   v[1] = Tree at address 0x10a6400
   ...
   v[98] = Tree at address 0x10bc8d8
   v[99] = Tree at address 0x10bcce8

before cmm_collect_now() and cmm_idle()-- mem_info(3):

'Small object heap: 0.08 MByte in 21 blocks (21 used)
Managed memory   : 0.10 MByte in 81 + 22 objects
Memory used by MM: 2.02 MByte total
                 : 0.00 MByte for inheap array
                 : 2.00 MByte for offheap array
Page size        : 4096 bytes
Block size       : 4096 bytes
GC threshold     : 7 blocks / 0.04 MByte
Debug code       : enabled
Memory roots     : 2 total, 2 active
Transient stack  : 1 objects

 Memory type    | size  | # inheap (blocks) | # malloced
---------------------------------------------------------
       cmm_stack |    40 |       0  (     0) |          1
 cmm_stack_chunk |  4096 |       1  (     1) |          0
          blob8 |     8 |       0  (     0) |          0
         blob16 |    16 |       0  (     0) |          0
         blob32 |    32 |       0  (     0) |          0
         blob64 |    64 |       0  (     0) |          0
        blob128 |   128 |       0  (     0) |          0
        blob256 |   256 |       0  (     0) |          0
           blob |     0 |       0  (     0) |          1
           refs |     0 |       0  (     0) |          0
           tree |  1024 |      80  (    20) |         20
'
cmm(mark): root at 0x7fffc814aef8 is not a managed address

Program received signal SIGABRT, Aborted.
0x00007f1bc5bf7a75 in raise () from /lib/libc.so.6
(gdb) bt
#0  0x00007f1bc5bf7a75 in raise () from /lib/libc.so.6
#1  0x00007f1bc5bfb5c0 in abort () from /lib/libc.so.6
#2  0x0000000000407b02 in mark () at src/mm.cpp:1725
#3  0x0000000000407f7b in mm_collect_now () at src/mm.cpp:2055
#4  0x00000000004019a2 in main (argc=2, argv=0x7fffc814b0a8) at test1.cpp:130

	*/

    // do collection in background
    while(cmm_idle()) cmm_idle();

    char* msg2 = strdup(cmm_info(3));
    printf("after cmm_collect_now() and cmm_idle()-- mem_info(3): '%s'\n", msg2);

    // do collection
    while(cmm_idle()) cmm_idle();

    cmm_collect_now();

    char* msg3 = strdup(cmm_info(3));
    printf("after 2nd attempt at collection: cmm_collect_now() and cmm_idle()-- mem_info(3): '%s'\n", msg3);

    return 0;
}

<commit_msg>don't do cmm_root, instead do CMM_anchor() to fix allocated pointers. Now I get a crash in dump_heap_stats (src/cmm_no_snapshot.cpp:2346) because cmm_typeof(CLRPTR(managed[i])) is returning -20840<commit_after>/*

  test1.cpp: figure out how to use libcmm garbage collection.

 */

//#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>

#include "cmm.h"

#include <vector>
using std::vector;

typedef struct tree_node Tree;
struct tree_node {
    Tree * left, * right;
    void * key;
    int size;   /* maintained to be the number of nodes rooted here */
};

typedef vector<Tree*> tree_v;
typedef tree_v::iterator tree_vit;

/* clear and mark function for libcmm */
static void clear_tree(Tree *t)
{
  //  printf("clear_tree() called! at %p\n",t);
    t->left = NULL;
    t->right = NULL;
    t->key = NULL;
}

static void mark_tree(Tree *t)
{
  //  printf("mark_tree() called! at %p\n",t);
    CMM_MARK(t->left);
    CMM_MARK(t->right);
    CMM_MARK(t->key);
}

mt_t mt_tree = mt_undefined;

#define MBYTE (1<<20)

/* typedef bool finalize_func_t(void *); */
/* global counter of number of finalizers run */
int nfinal = 0;

bool tree_finalizer(void* p) {
#if 0
  char buf[500];
  sprintf(buf,"/home/jaten/dj/strongref/libcmm/finalizer.log.number_%d.pid_%d__and_ppid_%d.tid_%ld",nfinal,getpid(),getppid(),syscall(SYS_gettid));
  FILE* finallog = fopen(buf,"w");
  fprintf(finallog,"%d time in tree_finalizer, now for object %p\n",nfinal++,p);
  fclose(finallog);
  sync();
#endif
  return true;
}

void fill_tree_vector(tree_v& v, int reps) {
  d();
  CMM_ENTER; // expands to:  void **__cmm_stack_pointer = _cmm_begin_anchored()
  for (int n = 0; n < reps; n++) {
       d();
       // allocate and discard all these lines
       Tree* root = (Tree*)cmm_alloc(mt_tree);
       // CMM_ANCHOR(root) won't protect them, b/c no root points to them, so they all get collected upon CMM_EXIT.
       // So instead we'll try to make them all roots:
       //cmm_root(root); // don't use CMM_ROOT, because that takes the address of its argument!
       // and don't use cmm_root b/c that won't protect them.
       CMM_ANCHOR(root);
       v.push_back(root);
       printf("v[%d]: root is managed? %d  \n",n,(int)cmm_ismanaged(root));
  }
  d();
  CMM_EXIT; // expands to: _cmm_end_anchored(__cmm_stack_pointer)
  d();
}

int main(int argc, char **argv)
{
  if (argc < 2) {
    fprintf(stderr,"supply number of trees to allocate and forget as the only argument to test1.\n");
    exit(1);
  }
  int reps = atoi(argv[1]);

  /* maually test that finalizer works */
  tree_finalizer(0);

    int   n = 0;
    Tree* root = 0;

    FILE* flog = fopen("test1-gc-test.log","w");

    int nbytes = 4096;
    int npages = nbytes / 4096;
    npages=1;

    cmm_init(npages, 0, flog); /* request memory in terms of npages, not nbytes */
    d();
    cmm_debug(true); /* jea debug add */

    mt_tree = CMM_REGTYPE("tree", 1024, clear_tree, mark_tree, tree_finalizer);

    n =0;

    char* msg0 = strdup(cmm_info(3));
    printf("prior to any allocation -- mem_info(3): '%s'\n", msg0);

    tree_v v;

    // call subroutine
    d();
    fill_tree_vector(v,reps);
    d();

    printf("Just allocated 100 Trees in a subroutine.\n");

    char* msg100 = strdup(cmm_info(3));
    printf("after 100 pointers cmm_anchored: mem_info(3): '%s'\n", msg100);

    int i = 0;
    for(tree_vit it = v.begin(); it != v.end(); ++it, ++i ) {
      printf("   v[%d] = Tree at address %p\n", i, *it);
    }

    char* msg1 = strdup(cmm_info(3));
    printf("before cmm_collect_now() and cmm_idle()-- mem_info(3): '%s'\n", msg1);

    root = 0;

    d();
    cmm_collect_now();

       /* Unfortunately on the cmm_collect_now() call, we are seeing:

   Just allocated 100 Trees in a subroutine, protecting them with CMM_ANCHOR().
   v[0] = Tree at address 0x10a6000
   v[1] = Tree at address 0x10a6400
   ...
   v[98] = Tree at address 0x10bc8d8
   v[99] = Tree at address 0x10bcce8

before cmm_collect_now() and cmm_idle()-- mem_info(3):

'Small object heap: 0.08 MByte in 21 blocks (21 used)
Managed memory   : 0.10 MByte in 81 + 22 objects
Memory used by MM: 2.02 MByte total
                 : 0.00 MByte for inheap array
                 : 2.00 MByte for offheap array
Page size        : 4096 bytes
Block size       : 4096 bytes
GC threshold     : 7 blocks / 0.04 MByte
Debug code       : enabled
Memory roots     : 2 total, 2 active
Transient stack  : 1 objects

 Memory type    | size  | # inheap (blocks) | # malloced
---------------------------------------------------------
       cmm_stack |    40 |       0  (     0) |          1
 cmm_stack_chunk |  4096 |       1  (     1) |          0
          blob8 |     8 |       0  (     0) |          0
         blob16 |    16 |       0  (     0) |          0
         blob32 |    32 |       0  (     0) |          0
         blob64 |    64 |       0  (     0) |          0
        blob128 |   128 |       0  (     0) |          0
        blob256 |   256 |       0  (     0) |          0
           blob |     0 |       0  (     0) |          1
           refs |     0 |       0  (     0) |          0
           tree |  1024 |      80  (    20) |         20
'
cmm(mark): root at 0x7fffc814aef8 is not a managed address

Program received signal SIGABRT, Aborted.
0x00007f1bc5bf7a75 in raise () from /lib/libc.so.6
(gdb) bt
#0  0x00007f1bc5bf7a75 in raise () from /lib/libc.so.6
#1  0x00007f1bc5bfb5c0 in abort () from /lib/libc.so.6
#2  0x0000000000407b02 in mark () at src/mm.cpp:1725
#3  0x0000000000407f7b in mm_collect_now () at src/mm.cpp:2055
#4  0x00000000004019a2 in main (argc=2, argv=0x7fffc814b0a8) at test1.cpp:130

	*/

    // do collection in background
    while(cmm_idle()) cmm_idle();

    char* msg2 = strdup(cmm_info(3));
    printf("after cmm_collect_now() and cmm_idle()-- mem_info(3): '%s'\n", msg2);

    // do collection
    while(cmm_idle()) cmm_idle();

    cmm_collect_now();

    char* msg3 = strdup(cmm_info(3));
    printf("after 2nd attempt at collection: cmm_collect_now() and cmm_idle()-- mem_info(3): '%s'\n", msg3);

    return 0;
}

<|endoftext|>


<commit_before><commit_msg>Fixed @since tags<commit_after><|endoftext|>


<commit_before>/*******************************************************************************
 * c7a/data/serializer.hpp
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_DATA_SERIALIZER_HEADER
#define C7A_DATA_SERIALIZER_HEADER

#include <string>
#include <cstring>
#include <utility>

//TODO(ts) this copies data. That is bad and makes me sad.

namespace c7a {
namespace data {

//! internal representation of data elements
typedef std::string Blob;

//! \namespace namespace to hide the implementations of serializers
namespace serializers {

template <class T>
struct Impl;

//! identity serializer from string to string
template <>
struct Impl<std::string>{
    static std::string Serialize(const std::string& x) {
        return x;
    }

    static std::string Deserialize(const std::string& x) {
        return x;
    }
};

//! serializer for int
template <>
struct Impl<int>{
    static std::string Serialize(const int& x) {
        return std::to_string(x);
    }

    static int Deserialize(const std::string& x) {
        return std::stoi(x);
    }
};

//! serializer for double
template <>
struct Impl<double>{
    static std::string Serialize(const double& x) {
        return std::to_string(x);
    }

    static double Deserialize(const std::string& x) {
        return std::stod(x);
    }
};

//! serializer for (string, int) tuples
template <>
struct Impl<std::pair<std::string, int> >{
    static std::string Serialize(const std::pair<std::string, int>& x) {
        std::size_t len = sizeof(int) + x.first.size();
        char result[len];
        std::memcpy(result, &(x.second), sizeof(int));
        std::memcpy(result + sizeof(int), x.first.c_str(), x.first.size());
        return std::string(result, len);
    }

    static std::pair<std::string, int> Deserialize(const std::string& x) {
        int i;
        std::size_t str_len = x.size() - sizeof(int);
        std::memcpy(&i, x.c_str(), sizeof(int));
        std::string s(x, sizeof(int), str_len);
        return std::pair<std::string, int>(s, i);
    }
};

} // namespace serializers

//! Serialize the type to std::string
template <class T>
inline std::string Serialize(const T& x) {
    return serializers::Impl<T>::Serialize(x);
}

//! Deserialize the std::string to the given type
template <class T>
inline T Deserialize(const std::string& x) {
    return serializers::Impl<T>::Deserialize(x);
}

} // namespace data
} // namespace c7a

#endif // !C7A_DATA_SERIALIZER_HEADER

/******************************************************************************/
<commit_msg>Adding generic integral type binary serializer. See new issue CA-127.<commit_after>/*******************************************************************************
 * c7a/data/serializer.hpp
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_DATA_SERIALIZER_HEADER
#define C7A_DATA_SERIALIZER_HEADER

#include <string>
#include <cstring>
#include <utility>
#include <cassert>

//TODO(ts) this copies data. That is bad and makes me sad.

namespace c7a {
namespace data {

//! internal representation of data elements
typedef std::string Blob;

//! \namespace namespace to hide the implementations of serializers
namespace serializers {

template <class T>
struct Impl;

//! identity serializer from string to string
template <>
struct Impl<std::string>{
    static std::string Serialize(const std::string& x) {
        return x;
    }

    static std::string Deserialize(const std::string& x) {
        return x;
    }
};

//! serializer for int
template <>
struct Impl<int>{
    static std::string Serialize(const int& x) {
        return std::to_string(x);
    }

    static int Deserialize(const std::string& x) {
        return std::stoi(x);
    }
};

//! serializer for double
template <>
struct Impl<double>{
    static std::string Serialize(const double& x) {
        return std::to_string(x);
    }

    static double Deserialize(const std::string& x) {
        return std::stod(x);
    }
};

//! serializer for (string, int) tuples
template <>
struct Impl<std::pair<std::string, int> >{
    static std::string Serialize(const std::pair<std::string, int>& x) {
        std::size_t len = sizeof(int) + x.first.size();
        char result[len];
        std::memcpy(result, &(x.second), sizeof(int));
        std::memcpy(result + sizeof(int), x.first.c_str(), x.first.size());
        return std::string(result, len);
    }

    static std::pair<std::string, int> Deserialize(const std::string& x) {
        int i;
        std::size_t str_len = x.size() - sizeof(int);
        std::memcpy(&i, x.c_str(), sizeof(int));
        std::string s(x, sizeof(int), str_len);
        return std::pair<std::string, int>(s, i);
    }
};

//! binary serializer for any integral type, usable as template.
template <typename Type>
struct GenericImpl {
    static std::string Serialize(const Type& v) {
        return std::string(reinterpret_cast<const char*>(&v), sizeof(v));
    }

    static Type        Deserialize(const std::string& s) {
        assert(s.size() == sizeof(Type));
        return Type(*reinterpret_cast<const Type*>(s.data()));
    }
};

template <>
struct Impl<std::pair<int, int> >: public GenericImpl<std::pair<int, int> >
{ };

} // namespace serializers

//! Serialize the type to std::string
template <class T>
inline std::string Serialize(const T& x) {
    return serializers::Impl<T>::Serialize(x);
}

//! Deserialize the std::string to the given type
template <class T>
inline T Deserialize(const std::string& x) {
    return serializers::Impl<T>::Deserialize(x);
}

} // namespace data
} // namespace c7a

#endif // !C7A_DATA_SERIALIZER_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before>// Copyright (C) 2011-2012 Sergey Zolotarev
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <cstring>
#include <ctime>
#include <exception>
#include <iterator>
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <amx/amx.h>
#include <amx/amxaux.h>
#ifdef _WIN32
	#include <windows.h>
	#include <sys/types.h>
	#include <sys/stat.h>
	#if !defined stat
		#define stat _stat
	#endif
#else
	#include <dirent.h>
	#include <fnmatch.h>
	#include <sys/stat.h>
#endif
#include "amxname.h"

static time_t GetMtime(const std::string filename) {
	struct stat attrib;
	stat(filename.c_str(), &attrib);
	return attrib.st_mtime;
}

class AmxFile {
public:
	static void FreeAmx(AMX *amx);

	explicit AmxFile(const std::string &name);

	bool IsLoaded() const {
		return amxPtr_.get() != 0;
	}

	const AMX *GetAmx() const {
		return amxPtr_.get();
	}

	const std::string &GetName() const {
		return name_;
	}

	std::time_t GetLastWriteTime() const {
		return last_write_;
	}

private:
	std::shared_ptr<AMX> amxPtr_;
	std::string name_;
	std::time_t last_write_;
};

AmxFile::AmxFile(const std::string &name)
	: name_(name)
	, last_write_(GetMtime(name))
	, amxPtr_(new AMX, FreeAmx)
{
	if (aux_LoadProgram(amxPtr_.get(), const_cast<char*>(name.c_str()), 0) != AMX_ERR_NONE) {
		amxPtr_.reset();
	}
}

void AmxFile::FreeAmx(AMX *amx) {
	aux_FreeProgram(amx);
	delete amx;
}

static std::unordered_map<std::string, AmxFile> scripts;
static std::unordered_map<AMX*, std::string> cachedNames;

template<typename OutputIterator>
static void GetFilesInDirectory(const std::string &dir,
								const std::string &pattern,
								OutputIterator result) {
#if defined _WIN32
	WIN32_FIND_DATA findFileData;
	HANDLE hFindFile = FindFirstFile((dir + "\\" + pattern).c_str(), &findFileData);
	if (hFindFile != INVALID_HANDLE_VALUE) {
		do {
			if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
				*result++ = dir + "\\" + findFileData.cFileName;
			}
		} while (FindNextFile(hFindFile, &findFileData) != 0);
		FindClose(hFindFile);
	}
#else
	DIR *dp;
	if ((dp = opendir(dir.c_str())) != 0) {
		struct dirent *dirp;
		while ((dirp = readdir(dp)) != 0) {
			if (!fnmatch(pattern.c_str(), dirp->d_name,
							FNM_CASEFOLD | FNM_NOESCAPE | FNM_PERIOD)) {
				*result++ = dir + "/" + dirp->d_name;
			}
		}
		closedir(dp);
	}
#endif
}

std::string GetAmxName(AMX_HEADER *amxhdr) {
	std::string result;

	std::list<std::string> files;
	GetFilesInDirectory("gamemodes", "*.amx", std::back_inserter(files));
	GetFilesInDirectory("filterscripts", "*.amx", std::back_inserter(files));

	std::for_each(files.begin(), files.end(), [](const std::string &file) {
		auto script_it = scripts.find(file);
		if (script_it == scripts.end() ||
				script_it->second.GetLastWriteTime() < GetMtime(file)) {
			if (script_it != scripts.end()) {
				scripts.erase(script_it);
			}
			AmxFile script_it(file);
			if (script_it.IsLoaded()) {
				scripts.insert(std::make_pair(file, script_it));
			}
		}
	});

	for (auto iterator = scripts.begin(); iterator != scripts.end(); ++iterator) {
		void *amxhdr2 = iterator->second.GetAmx()->base;
		if (std::memcmp(amxhdr, amxhdr2, sizeof(AMX_HEADER)) == 0) {
			result = iterator->first;
			break;
		}
	}

	return result;
}

std::string GetAmxName(AMX *amx) {
	std::string result;

	auto it = cachedNames.find(amx);
	if (it != cachedNames.end()) {
		result = it->second;
	} else {
		result = GetAmxName(reinterpret_cast<AMX_HEADER*>(amx->base));
		if (!result.empty()) {
			cachedNames.insert(std::make_pair(amx, result));
		}
	}

	return result;
}
<commit_msg>Pass parameter 'filename' as const ref.<commit_after>// Copyright (C) 2011-2012 Sergey Zolotarev
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <cstring>
#include <ctime>
#include <exception>
#include <iterator>
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <amx/amx.h>
#include <amx/amxaux.h>
#ifdef _WIN32
	#include <windows.h>
	#include <sys/types.h>
	#include <sys/stat.h>
	#if !defined stat
		#define stat _stat
	#endif
#else
	#include <dirent.h>
	#include <fnmatch.h>
	#include <sys/stat.h>
#endif
#include "amxname.h"

static time_t GetMtime(const std::string &filename) {
	struct stat attrib;
	stat(filename.c_str(), &attrib);
	return attrib.st_mtime;
}

class AmxFile {
public:
	static void FreeAmx(AMX *amx);

	explicit AmxFile(const std::string &name);

	bool IsLoaded() const {
		return amxPtr_.get() != 0;
	}

	const AMX *GetAmx() const {
		return amxPtr_.get();
	}

	const std::string &GetName() const {
		return name_;
	}

	std::time_t GetLastWriteTime() const {
		return last_write_;
	}

private:
	std::shared_ptr<AMX> amxPtr_;
	std::string name_;
	std::time_t last_write_;
};

AmxFile::AmxFile(const std::string &name)
	: name_(name)
	, last_write_(GetMtime(name))
	, amxPtr_(new AMX, FreeAmx)
{
	if (aux_LoadProgram(amxPtr_.get(), const_cast<char*>(name.c_str()), 0) != AMX_ERR_NONE) {
		amxPtr_.reset();
	}
}

void AmxFile::FreeAmx(AMX *amx) {
	aux_FreeProgram(amx);
	delete amx;
}

static std::unordered_map<std::string, AmxFile> scripts;
static std::unordered_map<AMX*, std::string> cachedNames;

template<typename OutputIterator>
static void GetFilesInDirectory(const std::string &dir,
								const std::string &pattern,
								OutputIterator result) {
#if defined _WIN32
	WIN32_FIND_DATA findFileData;
	HANDLE hFindFile = FindFirstFile((dir + "\\" + pattern).c_str(), &findFileData);
	if (hFindFile != INVALID_HANDLE_VALUE) {
		do {
			if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
				*result++ = dir + "\\" + findFileData.cFileName;
			}
		} while (FindNextFile(hFindFile, &findFileData) != 0);
		FindClose(hFindFile);
	}
#else
	DIR *dp;
	if ((dp = opendir(dir.c_str())) != 0) {
		struct dirent *dirp;
		while ((dirp = readdir(dp)) != 0) {
			if (!fnmatch(pattern.c_str(), dirp->d_name,
							FNM_CASEFOLD | FNM_NOESCAPE | FNM_PERIOD)) {
				*result++ = dir + "/" + dirp->d_name;
			}
		}
		closedir(dp);
	}
#endif
}

std::string GetAmxName(AMX_HEADER *amxhdr) {
	std::string result;

	std::list<std::string> files;
	GetFilesInDirectory("gamemodes", "*.amx", std::back_inserter(files));
	GetFilesInDirectory("filterscripts", "*.amx", std::back_inserter(files));

	std::for_each(files.begin(), files.end(), [](const std::string &file) {
		auto script_it = scripts.find(file);
		if (script_it == scripts.end() ||
				script_it->second.GetLastWriteTime() < GetMtime(file)) {
			if (script_it != scripts.end()) {
				scripts.erase(script_it);
			}
			AmxFile script_it(file);
			if (script_it.IsLoaded()) {
				scripts.insert(std::make_pair(file, script_it));
			}
		}
	});

	for (auto iterator = scripts.begin(); iterator != scripts.end(); ++iterator) {
		void *amxhdr2 = iterator->second.GetAmx()->base;
		if (std::memcmp(amxhdr, amxhdr2, sizeof(AMX_HEADER)) == 0) {
			result = iterator->first;
			break;
		}
	}

	return result;
}

std::string GetAmxName(AMX *amx) {
	std::string result;

	auto it = cachedNames.find(amx);
	if (it != cachedNames.end()) {
		result = it->second;
	} else {
		result = GetAmxName(reinterpret_cast<AMX_HEADER*>(amx->base));
		if (!result.empty()) {
			cachedNames.insert(std::make_pair(amx, result));
		}
	}

	return result;
}
<|endoftext|>