<commit_before>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "WidgetPrivateData.hpp"
#include "../TopLevelWidget.hpp"
#include "../Window.hpp"

START_NAMESPACE_DGL

// --------------------------------------------------------------------------------------------------------------------
// Widget

Widget::Widget(TopLevelWidget* const topLevelWidget)
    : pData(new PrivateData(this, topLevelWidget)) {}

Widget::Widget(Widget* const parentWidget)
    : pData(new PrivateData(this, parentWidget)) {}

Widget::~Widget()
{
    delete pData;
}

bool Widget::isVisible() const noexcept
{
    return pData->visible;
}

void Widget::setVisible(bool visible)
{
    if (pData->visible == visible)
        return;

    pData->visible = visible;
    repaint();

    // FIXME check case of hiding a previously visible widget, does it trigger a repaint?
}

void Widget::show()
{
    setVisible(true);
}

void Widget::hide()
{
    setVisible(false);
}

uint Widget::getWidth() const noexcept
{
    return pData->size.getWidth();
}

uint Widget::getHeight() const noexcept
{
    return pData->size.getHeight();
}

const Size<uint> Widget::getSize() const noexcept
{
    return pData->size;
}

void Widget::setWidth(uint width) noexcept
{
    if (pData->size.getWidth() == width)
        return;

    ResizeEvent ev;
    ev.oldSize = pData->size;
    ev.size    = Size<uint>(width, pData->size.getHeight());

    pData->size.setWidth(width);
    onResize(ev);

    repaint();
}

void Widget::setHeight(uint height) noexcept
{
    if (pData->size.getHeight() == height)
        return;

    ResizeEvent ev;
    ev.oldSize = pData->size;
    ev.size    = Size<uint>(pData->size.getWidth(), height);

    pData->size.setHeight(height);
    onResize(ev);

    repaint();
}

void Widget::setSize(uint width, uint height) noexcept
{
    setSize(Size<uint>(width, height));
}

void Widget::setSize(const Size<uint>& size) noexcept
{
    if (pData->size == size)
        return;

    ResizeEvent ev;
    ev.oldSize = pData->size;
    ev.size    = size;

    pData->size = size;
    onResize(ev);

    repaint();
}

Application& Widget::getApp() const noexcept
{
    DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr);
    return pData->topLevelWidget->getApp();
}

Window& Widget::getWindow() const noexcept
{
    DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr);
    return pData->topLevelWidget->getWindow();
}

const GraphicsContext& Widget::getGraphicsContext() const noexcept
{
    DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr);
    return pData->topLevelWidget->getWindow().getGraphicsContext();
}

TopLevelWidget* Widget::getTopLevelWidget() const noexcept
{
    return pData->topLevelWidget;
}

void Widget::repaint() noexcept
{
}

uint Widget::getId() const noexcept
{
    return pData->id;
}

void Widget::setId(uint id) noexcept
{
    pData->id = id;
}

bool Widget::onKeyboard(const KeyboardEvent&)
{
    return false;
}

bool Widget::onSpecial(const SpecialEvent&)
{
    return false;
}

bool Widget::onCharacterInput(const CharacterInputEvent&)
{
    return false;
}

bool Widget::onMouse(const MouseEvent&)
{
    return false;
}

bool Widget::onMotion(const MotionEvent&)
{
    return false;
}

bool Widget::onScroll(const ScrollEvent&)
{
    return false;
}

void Widget::onResize(const ResizeEvent&)
{
}

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

END_NAMESPACE_DGL
<commit_msg>Make widget pass events into subwidgets<commit_after>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "WidgetPrivateData.hpp"
#include "../TopLevelWidget.hpp"
#include "../Window.hpp"

START_NAMESPACE_DGL

// --------------------------------------------------------------------------------------------------------------------
// Widget

Widget::Widget(TopLevelWidget* const topLevelWidget)
    : pData(new PrivateData(this, topLevelWidget)) {}

Widget::Widget(Widget* const parentWidget)
    : pData(new PrivateData(this, parentWidget)) {}

Widget::~Widget()
{
    delete pData;
}

bool Widget::isVisible() const noexcept
{
    return pData->visible;
}

void Widget::setVisible(bool visible)
{
    if (pData->visible == visible)
        return;

    pData->visible = visible;
    repaint();

    // FIXME check case of hiding a previously visible widget, does it trigger a repaint?
}

void Widget::show()
{
    setVisible(true);
}

void Widget::hide()
{
    setVisible(false);
}

uint Widget::getWidth() const noexcept
{
    return pData->size.getWidth();
}

uint Widget::getHeight() const noexcept
{
    return pData->size.getHeight();
}

const Size<uint> Widget::getSize() const noexcept
{
    return pData->size;
}

void Widget::setWidth(uint width) noexcept
{
    if (pData->size.getWidth() == width)
        return;

    ResizeEvent ev;
    ev.oldSize = pData->size;
    ev.size    = Size<uint>(width, pData->size.getHeight());

    pData->size.setWidth(width);
    onResize(ev);

    repaint();
}

void Widget::setHeight(uint height) noexcept
{
    if (pData->size.getHeight() == height)
        return;

    ResizeEvent ev;
    ev.oldSize = pData->size;
    ev.size    = Size<uint>(pData->size.getWidth(), height);

    pData->size.setHeight(height);
    onResize(ev);

    repaint();
}

void Widget::setSize(uint width, uint height) noexcept
{
    setSize(Size<uint>(width, height));
}

void Widget::setSize(const Size<uint>& size) noexcept
{
    if (pData->size == size)
        return;

    ResizeEvent ev;
    ev.oldSize = pData->size;
    ev.size    = size;

    pData->size = size;
    onResize(ev);

    repaint();
}

Application& Widget::getApp() const noexcept
{
    DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr);
    return pData->topLevelWidget->getApp();
}

Window& Widget::getWindow() const noexcept
{
    DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr);
    return pData->topLevelWidget->getWindow();
}

const GraphicsContext& Widget::getGraphicsContext() const noexcept
{
    DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr);
    return pData->topLevelWidget->getWindow().getGraphicsContext();
}

TopLevelWidget* Widget::getTopLevelWidget() const noexcept
{
    return pData->topLevelWidget;
}

void Widget::repaint() noexcept
{
}

uint Widget::getId() const noexcept
{
    return pData->id;
}

void Widget::setId(uint id) noexcept
{
    pData->id = id;
}

bool Widget::onKeyboard(const KeyboardEvent& ev)
{
    return pData->giveKeyboardEventForSubWidgets(ev);
}

bool Widget::onSpecial(const SpecialEvent& ev)
{
    return pData->giveSpecialEventForSubWidgets(ev);
}

bool Widget::onCharacterInput(const CharacterInputEvent& ev)
{
    return pData->giveCharacterInputEventForSubWidgets(ev);
}

bool Widget::onMouse(const MouseEvent& ev)
{
    MouseEvent rev = ev;
    return pData->giveMouseEventForSubWidgets(rev);
}

bool Widget::onMotion(const MotionEvent& ev)
{
    MotionEvent rev = ev;
    return pData->giveMotionEventForSubWidgets(rev);
}

bool Widget::onScroll(const ScrollEvent& ev)
{
    ScrollEvent rev = ev;
    return pData->giveScrollEventForSubWidgets(rev);
}

void Widget::onResize(const ResizeEvent&)
{
}

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

END_NAMESPACE_DGL
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2015, Muhammad Shahzad Shafi <shahzad at voip-demos dot com>
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted per Mozilla Public License v2.0.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include <random>
#include <algorithm>

#include "itv_utils.h"

using namespace::std;

#ifndef _MSC_VER
// trim string from start
std::string &ltrim(std::string &s) {
	s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
	return s;
};

// trim string from end
std::string &rtrim(std::string &s) {
	s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
	return s;
};

// trim string from both ends
std::string &trim(std::string &s) {
	return ltrim(rtrim(s));
};

// split string into list according to given delimiter
std::list<std::string>* split(std::string& s, std::string& delimiter) {
	size_t last = 0, next = 0;
	std::list<std::string>* ret = new list<std::string>();
	while ((next = s.find(delimiter, last)) != string::npos) {
		ret->push_back(s.substr(last, next-last));
		last = next + 1;
	};
	ret->push_back(s.substr(last));
	return ret;
};
#endif

// generate a random number from 0 to given number
size_t generate_random(size_t max) {
	return get_random(0, max);
};

// generate a random number within range
size_t get_random(size_t min, size_t max) {
	std::random_device generator;
	std::uniform_int_distribution<size_t> distribution(min, max);
	return distribution(generator);
};

// convert codepoint to utf8 char
std::string to_utf8(size_t cp) {
	char c[5]={ 0x00,0x00,0x00,0x00,0x00 };
	if		(cp<=0x7F)		{ c[0] = cp;  }
	else if	(cp<=0x7FF)		{ c[0] = (cp>>6)+192; c[1] = (cp&63)+128; }
	else if	(0xd800<=cp && cp<=0xdfff) { } //invalid block of utf8
	else if	(cp<=0xFFFF)	{ c[0] = (cp>>12)+224; c[1]= ((cp>>6)&63)+128; c[2]=(cp&63)+128; }
	else if	(cp<=0x10FFFF)	{ c[0] = (cp>>18)+240; c[1] = ((cp>>12)&63)+128; c[2] = ((cp>>6)&63)+128; c[3]=(cp&63)+128; }
	return std::string(c);
}

// convert codepoints to utf8 string
std::string to_utf8(std::list<size_t>& msg) {
	std::string str;
	for (auto i=msg.begin(); i!=msg.end(); i++) { str += to_utf8(*i); };
	return str;
};

// converts utf8 string to codepoint list
std::list<size_t>* from_utf8(std::string& msg) {
	std::list<size_t> *ret = new std::list<size_t>();
	std::string::size_type len = msg.length();
	if (len < 1) return ret;

	for(std::string::size_type i=0; i<len; i++) {
		unsigned char u0 = msg[i+0];
		if (u0>=0 && u0<=127)	{ ret->push_back(u0); continue; };
		if ((i+1) < len) {
			unsigned char u1 = msg[++i];
			if (u0>=192 && u0<=223)	{ ret->push_back((u0-192)*64 + (u1-128)); continue; };
			if (u0==0xed && (u1 & 0xa0) == 0xa0) { continue; }; //codepoints 0xd800 to 0xdfff are not valid
			if ((i+2) < len) {
				unsigned char u2 = msg[++i];
				if (u0>=224 && u0<=239)	{ ret->push_back((u0-224)*4096 + (u1-128)*64 + (u2-128)); continue; };
				if ((i+3) < len) {
					unsigned char u3 = msg[++i];
					if (u0>=240 && u0<=247)	{ ret->push_back((u0-240)*262144 + (u1-128)*4096 + (u2-128)*64 + (u3-128)); continue; };
				};
			};
		};
	};

	return ret;
};

<commit_msg>fixed a bug that causing wrong utf8 conversion when code point > 0x800<commit_after>/*
 * Copyright (c) 2013-2015, Muhammad Shahzad Shafi <shahzad at voip-demos dot com>
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted per Mozilla Public License v2.0.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include <random>
#include <algorithm>

#include "itv_utils.h"

using namespace::std;

#ifndef _MSC_VER
// trim string from start
std::string &ltrim(std::string &s) {
	s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
	return s;
};

// trim string from end
std::string &rtrim(std::string &s) {
	s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
	return s;
};

// trim string from both ends
std::string &trim(std::string &s) {
	return ltrim(rtrim(s));
};

// split string into list according to given delimiter
std::list<std::string>* split(std::string& s, std::string& delimiter) {
	size_t last = 0, next = 0;
	std::list<std::string>* ret = new list<std::string>();
	while ((next = s.find(delimiter, last)) != string::npos) {
		ret->push_back(s.substr(last, next-last));
		last = next + 1;
	};
	ret->push_back(s.substr(last));
	return ret;
};
#endif

// generate a random number from 0 to given number
size_t generate_random(size_t max) {
	return get_random(0, max);
};

// generate a random number within range
size_t get_random(size_t min, size_t max) {
	std::random_device generator;
	std::uniform_int_distribution<size_t> distribution(min, max);
	return distribution(generator);
};

// convert codepoint to utf8 char
std::string to_utf8(size_t cp) {
	char c[5]={ 0x00,0x00,0x00,0x00,0x00 };
	if		(cp<=0x7F)		{ c[0] = cp;  }
	else if	(cp<=0x7FF)		{ c[0] = (cp>>6)+192; c[1] = (cp&63)+128; }
	else if	(0xd800<=cp && cp<=0xdfff) { } //invalid block of utf8
	else if	(cp<=0xFFFF)	{ c[0] = (cp>>12)+224; c[1]= ((cp>>6)&63)+128; c[2]=(cp&63)+128; }
	else if	(cp<=0x10FFFF)	{ c[0] = (cp>>18)+240; c[1] = ((cp>>12)&63)+128; c[2] = ((cp>>6)&63)+128; c[3]=(cp&63)+128; }
	return std::string(c);
}

// convert codepoints to utf8 string
std::string to_utf8(std::list<size_t>& msg) {
	std::string str = std::string();
	for (auto i=msg.begin(); i!=msg.end(); i++) { str += to_utf8(*i); };
	return str;
};

// converts utf8 string to codepoint list
std::list<size_t>* from_utf8(std::string& msg) {
	std::list<size_t> *ret = new std::list<size_t>();
	std::string::size_type len = msg.length();
	if (len < 1) return ret;

	for(std::string::size_type i=0; i<len; i++) {
		unsigned char u0 = msg[i+0];
		if (u0>=0 && u0<=127)	{ ret->push_back(u0); continue; };
		if ((i+1) < len) {
			unsigned char u1 = msg[++i];
			if (u0>=192 && u0<=223)	{ ret->push_back((u0-192)*64 + (u1-128)); continue; };
			if (u0==0xed && (u1 & 0xa0) == 0xa0) { continue; }; //codepoints 0xd800 to 0xdfff are not valid
			if ((i+1) < len) {
				unsigned char u2 = msg[++i];
				if (u0>=224 && u0<=239)	{ ret->push_back((u0-224)*4096 + (u1-128)*64 + (u2-128)); continue; };
				if ((i+1) < len) {
					unsigned char u3 = msg[++i];
					if (u0>=240 && u0<=247)	{ ret->push_back((u0-240)*262144 + (u1-128)*4096 + (u2-128)*64 + (u3-128)); continue; };
				};
			};
		};
	};

	return ret;
};

<|endoftext|>


<commit_before>#include "BufferManager.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

ostream& operator<< (ostream &out, handshake_container_t &hand)
{
  out << "hand:" << " ";
  out << hand.valid;
  out << hand.mem_released;
  out << hand.isFirstInsn;
  out << hand.isLastInsn;
  out << hand.killThread;
  out << " ";
  out << hand.mem_buffer.size();
  out << " ";
  out << "pc:" << hand.handshake.pc << " ";
  out << "coreid:" << hand.handshake.coreID << " ";
  out << "npc:" << hand.handshake.npc << " ";
  out << "tpc:" << hand.handshake.tpc << " ";
  out << "brtaken:" << hand.handshake.brtaken << " ";
  out << "ins:" << hand.handshake.ins << " ";
  out << "flags:" << hand.handshake.sleep_thread << hand.handshake.resume_thread;
  out << hand.handshake.iteration_correction << hand.handshake.real;
  out << hand.handshake.in_critical_section;
  out << " slicenum:" << hand.handshake.slice_num << " ";
  out << "feederslicelen:" << hand.handshake.feeder_slice_length << " ";
  out << "feedersliceweight:" << hand.handshake.slice_weight_times_1000 << " ";
  out.flush();
  return out;
}

BufferManager::BufferManager()
{
}

handshake_container_t* BufferManager::front(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);
  assert(queueSizes_[tid] > 0);
  assert(consumeBuffer_[tid]->size() > 0);

  ReleaseLock(locks_[tid]);
  return consumeBuffer_[tid]->front();
}

handshake_container_t* BufferManager::back(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);
  assert(queueSizes_[tid] > 0);
  assert(produceBuffer_[tid]->size() > 0);
  ReleaseLock(locks_[tid]);
  return produceBuffer_[tid]->back();
}

bool BufferManager::empty(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);
  bool result = queueSizes_[tid] == 0;
  ReleaseLock(locks_[tid]);
  return result;
}

void BufferManager::push(THREADID tid, handshake_container_t* handshake, bool fromILDJIT)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);

  handshake_container_t* free = getPooledHandshake(tid, fromILDJIT);
  bool first = free->isFirstInsn;
  *free = *handshake;
  free->isFirstInsn = first;

  produceBuffer_[tid]->push(free);
  queueSizes_[tid]++;
  ReleaseLock(locks_[tid]);
}

void BufferManager::pop(THREADID tid, handshake_container_t* handshake)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);

  assert(queueSizes_[tid] > 0);
  assert(consumeBuffer_[tid]->size() > 0);
  consumeBuffer_[tid]->pop();

  releasePooledHandshake(tid, handshake);
  queueSizes_[tid]--;
  ReleaseLock(locks_[tid]);
}

bool BufferManager::hasThread(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  bool result = queueSizes_.count(tid);
  ReleaseLock(locks_[tid]);
  return (result != 0);
}

unsigned int BufferManager::size()
{
  GetLock(locks_[tid], tid+1);
  unsigned int result = queueSizes_.size();
  ReleaseLock(locks_[tid]);
  return result;
}

void BufferManager::checkFirstAccess(THREADID tid)
{
  if(queueSizes_.count(tid) == 0) {

    PIN_Yield();
    sleep(5);
    PIN_Yield();

    queueSizes_[tid] = 0;
    consumeBuffer_[tid] = new Buffer();
    produceBuffer_[tid] = new Buffer();

    for (int i=0; i < 50000; i++) {
      handshake_container_t* new_handshake = new handshake_container_t();
      handshake_pool_[tid].push(new_handshake);
    }

    locks_[tid] = new PIN_LOCK();
    InitLock(locks_[tid]);

    char s_tid[100];
    sprintf(s_tid, "%d", tid);

    string logName = "./output_ring_cache/handshake_" + string(s_tid) + ".log";
    logs_[tid] = new ofstream();
    (*(logs_[tid])).open(logName.c_str());
  }
}

handshake_container_t* BufferManager::getPooledHandshake(THREADID tid, bool fromILDJIT)
{
  checkFirstAccess(tid);

  handshake_queue_t *pool;
  pool = &(handshake_pool_[tid]);

  long long int spins = 0;
  while(pool->empty()) {
    ReleaseLock(&simbuffer_lock);
    PIN_Yield();
    GetLock(&simbuffer_lock, tid+1);
    spins++;
    if(spins >= 7000000LL) {
      cerr << tid << " [getPooledHandshake()]: That's a lot of spins!" << endl;
      spins = 0;
    }
  }

  handshake_container_t* result = pool->front();
  ASSERTX(result != NULL);

  pool->pop();

  if((didFirstInsn_.count(tid) == 0) && (!fromILDJIT)) {
    result->isFirstInsn = true;
    didFirstInsn_[tid] = true;
  }
  else {
    result->isFirstInsn = false;
  }

  return result;
}

void BufferManager::releasePooledHandshake(THREADID tid, handshake_container_t* handshake)
{
  handshake_pool_[tid].push(handshake);
  return;
}

bool BufferManager::isFirstInsn(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  bool isFirst = (didFirstInsn_.count(tid) == 0);
  ReleaseLock(locks_[tid]);
  return isFirst;
}
<commit_msg>compile error fixed from last commit<commit_after>#include "BufferManager.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

ostream& operator<< (ostream &out, handshake_container_t &hand)
{
  out << "hand:" << " ";
  out << hand.valid;
  out << hand.mem_released;
  out << hand.isFirstInsn;
  out << hand.isLastInsn;
  out << hand.killThread;
  out << " ";
  out << hand.mem_buffer.size();
  out << " ";
  out << "pc:" << hand.handshake.pc << " ";
  out << "coreid:" << hand.handshake.coreID << " ";
  out << "npc:" << hand.handshake.npc << " ";
  out << "tpc:" << hand.handshake.tpc << " ";
  out << "brtaken:" << hand.handshake.brtaken << " ";
  out << "ins:" << hand.handshake.ins << " ";
  out << "flags:" << hand.handshake.sleep_thread << hand.handshake.resume_thread;
  out << hand.handshake.iteration_correction << hand.handshake.real;
  out << hand.handshake.in_critical_section;
  out << " slicenum:" << hand.handshake.slice_num << " ";
  out << "feederslicelen:" << hand.handshake.feeder_slice_length << " ";
  out << "feedersliceweight:" << hand.handshake.slice_weight_times_1000 << " ";
  out.flush();
  return out;
}

BufferManager::BufferManager()
{
}

handshake_container_t* BufferManager::front(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);
  assert(queueSizes_[tid] > 0);
  assert(consumeBuffer_[tid]->size() > 0);

  ReleaseLock(locks_[tid]);
  return consumeBuffer_[tid]->front();
}

handshake_container_t* BufferManager::back(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);
  assert(queueSizes_[tid] > 0);
  assert(produceBuffer_[tid]->size() > 0);
  ReleaseLock(locks_[tid]);
  return produceBuffer_[tid]->back();
}

bool BufferManager::empty(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);
  bool result = queueSizes_[tid] == 0;
  ReleaseLock(locks_[tid]);
  return result;
}

void BufferManager::push(THREADID tid, handshake_container_t* handshake, bool fromILDJIT)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);

  handshake_container_t* free = getPooledHandshake(tid, fromILDJIT);
  bool first = free->isFirstInsn;
  *free = *handshake;
  free->isFirstInsn = first;

  produceBuffer_[tid]->push(free);
  queueSizes_[tid]++;
  ReleaseLock(locks_[tid]);
}

void BufferManager::pop(THREADID tid, handshake_container_t* handshake)
{
  GetLock(locks_[tid], tid+1);
  checkFirstAccess(tid);

  assert(queueSizes_[tid] > 0);
  assert(consumeBuffer_[tid]->size() > 0);
  consumeBuffer_[tid]->pop();

  releasePooledHandshake(tid, handshake);
  queueSizes_[tid]--;
  ReleaseLock(locks_[tid]);
}

bool BufferManager::hasThread(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  bool result = queueSizes_.count(tid);
  ReleaseLock(locks_[tid]);
  return (result != 0);
}

unsigned int BufferManager::size()
{
  unsigned int result = queueSizes_.size();
  return result;
}

void BufferManager::checkFirstAccess(THREADID tid)
{
  if(queueSizes_.count(tid) == 0) {

    PIN_Yield();
    sleep(5);
    PIN_Yield();

    queueSizes_[tid] = 0;
    consumeBuffer_[tid] = new Buffer();
    produceBuffer_[tid] = new Buffer();

    for (int i=0; i < 50000; i++) {
      handshake_container_t* new_handshake = new handshake_container_t();
      handshake_pool_[tid].push(new_handshake);
    }

    locks_[tid] = new PIN_LOCK();
    InitLock(locks_[tid]);

    char s_tid[100];
    sprintf(s_tid, "%d", tid);

    string logName = "./output_ring_cache/handshake_" + string(s_tid) + ".log";
    logs_[tid] = new ofstream();
    (*(logs_[tid])).open(logName.c_str());
  }
}

handshake_container_t* BufferManager::getPooledHandshake(THREADID tid, bool fromILDJIT)
{
  checkFirstAccess(tid);

  handshake_queue_t *pool;
  pool = &(handshake_pool_[tid]);

  long long int spins = 0;
  while(pool->empty()) {
    ReleaseLock(&simbuffer_lock);
    PIN_Yield();
    GetLock(&simbuffer_lock, tid+1);
    spins++;
    if(spins >= 7000000LL) {
      cerr << tid << " [getPooledHandshake()]: That's a lot of spins!" << endl;
      spins = 0;
    }
  }

  handshake_container_t* result = pool->front();
  ASSERTX(result != NULL);

  pool->pop();

  if((didFirstInsn_.count(tid) == 0) && (!fromILDJIT)) {
    result->isFirstInsn = true;
    didFirstInsn_[tid] = true;
  }
  else {
    result->isFirstInsn = false;
  }

  return result;
}

void BufferManager::releasePooledHandshake(THREADID tid, handshake_container_t* handshake)
{
  handshake_pool_[tid].push(handshake);
  return;
}

bool BufferManager::isFirstInsn(THREADID tid)
{
  GetLock(locks_[tid], tid+1);
  bool isFirst = (didFirstInsn_.count(tid) == 0);
  ReleaseLock(locks_[tid]);
  return isFirst;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "DeclCollector.h"

#include "IncrementalParser.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"

using namespace clang;

namespace {
  ///\brief Return true if this decl (which comes from an AST file) should
  /// not be sent to CodeGen. The module is assumed to describe the contents
  /// of a library; symbols inside the library must thus not be reemitted /
  /// duplicated by CodeGen.
  ///
  static bool shouldIgnore(const Decl* D) {
    // This function is called for all "deserialized" decls, where the
    // "deserialized" decl either really comes from an AST file or from
    // a header that's loaded to import the AST for a library with a dictionary
    // (the non-PCM case).
    //
    // Functions that are inlined must be sent to CodeGen - they will not have a
    // symbol in the library.
    if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
      if (D->isFromASTFile()) {
        return !FD->hasBody();
      } else {
        // If the decl must be emitted then it will be in the library.
        // If not, we must expose it to CodeGen now because it might
        // not be in the library. Does this correspond to a weak symbol
        // by definition?
        return !(FD->isInlined() || FD->isTemplateInstantiation());
      }
    }
    // Don't codegen statics coming in from a module; they are already part of
    // the library.
    // We do need to expose static variables from template instantiations.
    if (const VarDecl* VD = dyn_cast<VarDecl>(D))
      if (VD->hasGlobalStorage() && !VD->getType().isConstQualified()
          && VD->getTemplateSpecializationKind() == TSK_Undeclared)
        return true;
    return false;
  }
}

namespace cling {
  ///\brief Serves as DeclCollector's connector to the PPCallbacks interface.
  ///
  class DeclCollector::PPAdapter : public clang::PPCallbacks {
    cling::DeclCollector* m_Parent;

    void MacroDirective(const clang::Token& MacroNameTok,
                        const clang::MacroDirective* MD) {
      assert(m_Parent->m_CurTransaction && "Missing transction");
      Transaction::MacroDirectiveInfo MDE(MacroNameTok.getIdentifierInfo(), MD);
      m_Parent->m_CurTransaction->append(MDE);
    }

  public:
    PPAdapter(cling::DeclCollector* P) : m_Parent(P) {}

    /// \name PPCallbacks overrides
    /// Macro support
    void MacroDefined(const clang::Token& MacroNameTok,
                      const clang::MacroDirective* MD) final {
      MacroDirective(MacroNameTok, MD);
    }

    /// \name PPCallbacks overrides
    /// Macro support
    void MacroUndefined(const clang::Token& MacroNameTok,
                        const clang::MacroDefinition& MD,
                        const clang::MacroDirective* Undef) final {
      if (Undef)
        MacroDirective(MacroNameTok, Undef);
    }
  };

  void DeclCollector::Setup(IncrementalParser* IncrParser, ASTConsumer* Consumer,
                            clang::Preprocessor& PP) {
    m_IncrParser = IncrParser;
    m_Consumer = Consumer;
    PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new PPAdapter(this)));
  }

  bool DeclCollector::comesFromASTReader(DeclGroupRef DGR) const {
    assert(!DGR.isNull() && "DeclGroupRef is Null!");
    assert(m_CurTransaction && "No current transaction when deserializing");
    if (m_CurTransaction->getCompilationOpts().CodeGenerationForModule)
      return true;

    // Take the first/only decl in the group.
    Decl* D = *DGR.begin();
    return D->isFromASTFile();
  }

  bool DeclCollector::comesFromASTReader(const Decl* D) const {
    // The operation is const but clang::DeclGroupRef doesn't allow us to
    // express it.
    return comesFromASTReader(DeclGroupRef(const_cast<Decl*>(D)));
  }

  // pin the vtable here.
  DeclCollector::~DeclCollector() { }

 ASTTransformer::Result DeclCollector::TransformDecl(Decl* D) const {
    // We are sure it's safe to pipe it through the transformers
    // Consume late transformers init
    for (size_t i = 0; D && i < m_TransactionTransformers.size(); ++i) {
      ASTTransformer::Result NewDecl
        = m_TransactionTransformers[i]->Transform(D, m_CurTransaction);
      if (!NewDecl.getInt()) {
        m_CurTransaction->setIssuedDiags(Transaction::kErrors);
        return NewDecl;
      }
      D = NewDecl.getPointer();
    }
    if (FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D)) {
      if (utils::Analyze::IsWrapper(FD)) {
        for (size_t i = 0; D && i < m_WrapperTransformers.size(); ++i) {
          ASTTransformer::Result NewDecl
           = m_WrapperTransformers[i]->Transform(D, m_CurTransaction);
          if (!NewDecl.getInt()) {
            m_CurTransaction->setIssuedDiags(Transaction::kErrors);
            return NewDecl;
          }
          D = NewDecl.getPointer();
        }
      }
    }
    return ASTTransformer::Result(D, true);
  }

  bool DeclCollector::Transform(DeclGroupRef& DGR) {
    // Do not tranform recursively, e.g. when emitting a DeclExtracted decl.
    if (m_Transforming)
      return true;

    struct TransformingRAII {
      bool& m_Transforming;
      TransformingRAII(bool& Transforming): m_Transforming(Transforming) {
        m_Transforming = true;
      }
      ~TransformingRAII() { m_Transforming = false; }
    } transformingUpdater(m_Transforming);

    llvm::SmallVector<Decl*, 4> ReplacedDecls;
    bool HaveReplacement = false;
    for (Decl* D: DGR) {
      ASTTransformer::Result NewDecl = TransformDecl(D);
      if (!NewDecl.getInt())
        return false;
      HaveReplacement |= (NewDecl.getPointer() != D);
      if (NewDecl.getPointer())
        ReplacedDecls.push_back(NewDecl.getPointer());
    }
    if (HaveReplacement)
      DGR = DeclGroupRef::Create((*DGR.begin())->getASTContext(),
                                 ReplacedDecls.data(), ReplacedDecls.size());
    return true;
  }

  bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
    if (!Transform(DGR))
      return false;

    if (DGR.isNull())
      return true;

    assert(m_CurTransaction && "Missing transction");
    Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleTopLevelDecl);
    m_CurTransaction->append(DCI);
    if (!m_Consumer
        || getTransaction()->getIssuedDiags() == Transaction::kErrors)
      return true;

    if (comesFromASTReader(DGR)) {
      for (DeclGroupRef::iterator DI = DGR.begin(), DE = DGR.end();
           DI != DE; ++DI) {
        DeclGroupRef SplitDGR(*DI);
        // FIXME: The special namespace treatment (not sending itself to
        // CodeGen, but only its content - if the contained decl should be
        // emitted) works around issue with the static initialization when
        // having a PCH and loading a library. We don't want to generate
        // code for the static that will come through the library.
        //
        // This will be fixed with the clang::Modules. Make sure we remember.
        // assert(!getCI()->getLangOpts().Modules && "Please revisit!");
        if (NamespaceDecl* ND = dyn_cast<NamespaceDecl>(*DI)) {
          for (NamespaceDecl::decl_iterator NDI = ND->decls_begin(),
               EN = ND->decls_end(); NDI != EN; ++NDI) {
            // Recurse over decls inside the namespace, like
            // CodeGenModule::EmitNamespace() does.
            if (!shouldIgnore(*NDI))
              m_Consumer->HandleTopLevelDecl(DeclGroupRef(*NDI));
          }
        } else if (!shouldIgnore(*DI)) {
          m_Consumer->HandleTopLevelDecl(DeclGroupRef(*DI));
        }
        continue;
      }
    } else {
      m_Consumer->HandleTopLevelDecl(DGR);
    }
    return true;
  }

  void DeclCollector::HandleInterestingDecl(DeclGroupRef DGR) {
    assert(m_CurTransaction && "Missing transction");
    Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleInterestingDecl);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DGR) || !shouldIgnore(*DGR.begin())))
      m_Consumer->HandleTopLevelDecl(DGR);
  }

  void DeclCollector::HandleTagDeclDefinition(TagDecl* TD) {
    assert(m_CurTransaction && "Missing transction");
    Transaction::DelayCallInfo DCI(DeclGroupRef(TD),
                                   Transaction::kCCIHandleTagDeclDefinition);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(TD))
            || !shouldIgnore(TD)))
      m_Consumer->HandleTagDeclDefinition(TD);
  }

  void DeclCollector::HandleInvalidTagDeclDefinition(clang::TagDecl *TD){
    assert(m_CurTransaction && "Missing transction");
    Transaction::DelayCallInfo DCI(DeclGroupRef(TD),
                                   Transaction::kCCIHandleTagDeclDefinition);
    m_CurTransaction->append(DCI);
    m_CurTransaction->setIssuedDiags(Transaction::kErrors);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(TD))
            || !shouldIgnore(TD)))
      m_Consumer->HandleInvalidTagDeclDefinition(TD);
  }

  void DeclCollector::HandleVTable(CXXRecordDecl* RD) {
    assert(m_CurTransaction && "Missing transction");
    Transaction::DelayCallInfo DCI(DeclGroupRef(RD),
                                   Transaction::kCCIHandleVTable);
    m_CurTransaction->append(DCI);

    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(RD))
            || !shouldIgnore(RD)))
      m_Consumer->HandleVTable(RD);
    // Intentional no-op. It comes through Sema::DefineUsedVTables, which
    // comes either Sema::ActOnEndOfTranslationUnit or while instantiating a
    // template. In our case we will do it on transaction commit, without
    // keeping track of used vtables, because we have cases where we bypass the
    // clang/AST and directly ask the module so that we have to generate
    // everything without extra smartness.
  }

  void DeclCollector::CompleteTentativeDefinition(VarDecl* VD) {
    assert(m_CurTransaction && "Missing transction");
    // C has tentative definitions which we might need to deal with when running
    // in C mode.
    Transaction::DelayCallInfo DCI(DeclGroupRef(VD),
                                   Transaction::kCCICompleteTentativeDefinition);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(VD))
            || !shouldIgnore(VD)))
    m_Consumer->CompleteTentativeDefinition(VD);
  }

  void DeclCollector::HandleTranslationUnit(ASTContext& Ctx) {
    //if (m_Consumer)
    //  m_Consumer->HandleTranslationUnit(Ctx);
  }

  void DeclCollector::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
    assert(m_CurTransaction && "Missing transction");
    Transaction::DelayCallInfo DCI(DeclGroupRef(D),
                                   Transaction::kCCIHandleCXXImplicitFunctionInstantiation);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(D))
            || !shouldIgnore(D)))
    m_Consumer->HandleCXXImplicitFunctionInstantiation(D);
  }

  void DeclCollector::HandleCXXStaticMemberVarInstantiation(VarDecl *D) {
    assert(m_CurTransaction && "Missing transction");
    Transaction::DelayCallInfo DCI(DeclGroupRef(D),
                                   Transaction::kCCIHandleCXXStaticMemberVarInstantiation);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(D))
            || !shouldIgnore(D)))
    m_Consumer->HandleCXXStaticMemberVarInstantiation(D);
  }

} // namespace cling
<commit_msg>[cxxmodules] Print stacktrace before aborting on a missing exception.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "DeclCollector.h"

#include "IncrementalParser.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"
#include "llvm/Support/Signals.h"

using namespace clang;

namespace {
  ///\brief Return true if this decl (which comes from an AST file) should
  /// not be sent to CodeGen. The module is assumed to describe the contents
  /// of a library; symbols inside the library must thus not be reemitted /
  /// duplicated by CodeGen.
  ///
  static bool shouldIgnore(const Decl* D) {
    // This function is called for all "deserialized" decls, where the
    // "deserialized" decl either really comes from an AST file or from
    // a header that's loaded to import the AST for a library with a dictionary
    // (the non-PCM case).
    //
    // Functions that are inlined must be sent to CodeGen - they will not have a
    // symbol in the library.
    if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
      if (D->isFromASTFile()) {
        return !FD->hasBody();
      } else {
        // If the decl must be emitted then it will be in the library.
        // If not, we must expose it to CodeGen now because it might
        // not be in the library. Does this correspond to a weak symbol
        // by definition?
        return !(FD->isInlined() || FD->isTemplateInstantiation());
      }
    }
    // Don't codegen statics coming in from a module; they are already part of
    // the library.
    // We do need to expose static variables from template instantiations.
    if (const VarDecl* VD = dyn_cast<VarDecl>(D))
      if (VD->hasGlobalStorage() && !VD->getType().isConstQualified()
          && VD->getTemplateSpecializationKind() == TSK_Undeclared)
        return true;
    return false;
  }

  /// \brief Asserts that the given transaction is not null, otherwise prints a
  /// stack trace to stderr and aborts execution.
  static void assertHasTransaction(const cling::Transaction* T) {
    if (!T) {
      llvm::sys::PrintStackTrace(llvm::errs());
      llvm_unreachable("Missing transaction during deserialization!");
    }
  }
}

namespace cling {
  ///\brief Serves as DeclCollector's connector to the PPCallbacks interface.
  ///
  class DeclCollector::PPAdapter : public clang::PPCallbacks {
    cling::DeclCollector* m_Parent;

    void MacroDirective(const clang::Token& MacroNameTok,
                        const clang::MacroDirective* MD) {
      assertHasTransaction(m_Parent->m_CurTransaction);
      Transaction::MacroDirectiveInfo MDE(MacroNameTok.getIdentifierInfo(), MD);
      m_Parent->m_CurTransaction->append(MDE);
    }

  public:
    PPAdapter(cling::DeclCollector* P) : m_Parent(P) {}

    /// \name PPCallbacks overrides
    /// Macro support
    void MacroDefined(const clang::Token& MacroNameTok,
                      const clang::MacroDirective* MD) final {
      MacroDirective(MacroNameTok, MD);
    }

    /// \name PPCallbacks overrides
    /// Macro support
    void MacroUndefined(const clang::Token& MacroNameTok,
                        const clang::MacroDefinition& MD,
                        const clang::MacroDirective* Undef) final {
      if (Undef)
        MacroDirective(MacroNameTok, Undef);
    }
  };

  void DeclCollector::Setup(IncrementalParser* IncrParser, ASTConsumer* Consumer,
                            clang::Preprocessor& PP) {
    m_IncrParser = IncrParser;
    m_Consumer = Consumer;
    PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new PPAdapter(this)));
  }

  bool DeclCollector::comesFromASTReader(DeclGroupRef DGR) const {
    assert(!DGR.isNull() && "DeclGroupRef is Null!");
    assertHasTransaction(m_CurTransaction);
    if (m_CurTransaction->getCompilationOpts().CodeGenerationForModule)
      return true;

    // Take the first/only decl in the group.
    Decl* D = *DGR.begin();
    return D->isFromASTFile();
  }

  bool DeclCollector::comesFromASTReader(const Decl* D) const {
    // The operation is const but clang::DeclGroupRef doesn't allow us to
    // express it.
    return comesFromASTReader(DeclGroupRef(const_cast<Decl*>(D)));
  }

  // pin the vtable here.
  DeclCollector::~DeclCollector() { }

 ASTTransformer::Result DeclCollector::TransformDecl(Decl* D) const {
    // We are sure it's safe to pipe it through the transformers
    // Consume late transformers init
    for (size_t i = 0; D && i < m_TransactionTransformers.size(); ++i) {
      ASTTransformer::Result NewDecl
        = m_TransactionTransformers[i]->Transform(D, m_CurTransaction);
      if (!NewDecl.getInt()) {
        m_CurTransaction->setIssuedDiags(Transaction::kErrors);
        return NewDecl;
      }
      D = NewDecl.getPointer();
    }
    if (FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D)) {
      if (utils::Analyze::IsWrapper(FD)) {
        for (size_t i = 0; D && i < m_WrapperTransformers.size(); ++i) {
          ASTTransformer::Result NewDecl
           = m_WrapperTransformers[i]->Transform(D, m_CurTransaction);
          if (!NewDecl.getInt()) {
            m_CurTransaction->setIssuedDiags(Transaction::kErrors);
            return NewDecl;
          }
          D = NewDecl.getPointer();
        }
      }
    }
    return ASTTransformer::Result(D, true);
  }

  bool DeclCollector::Transform(DeclGroupRef& DGR) {
    // Do not tranform recursively, e.g. when emitting a DeclExtracted decl.
    if (m_Transforming)
      return true;

    struct TransformingRAII {
      bool& m_Transforming;
      TransformingRAII(bool& Transforming): m_Transforming(Transforming) {
        m_Transforming = true;
      }
      ~TransformingRAII() { m_Transforming = false; }
    } transformingUpdater(m_Transforming);

    llvm::SmallVector<Decl*, 4> ReplacedDecls;
    bool HaveReplacement = false;
    for (Decl* D: DGR) {
      ASTTransformer::Result NewDecl = TransformDecl(D);
      if (!NewDecl.getInt())
        return false;
      HaveReplacement |= (NewDecl.getPointer() != D);
      if (NewDecl.getPointer())
        ReplacedDecls.push_back(NewDecl.getPointer());
    }
    if (HaveReplacement)
      DGR = DeclGroupRef::Create((*DGR.begin())->getASTContext(),
                                 ReplacedDecls.data(), ReplacedDecls.size());
    return true;
  }

  bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
    if (!Transform(DGR))
      return false;

    if (DGR.isNull())
      return true;

    assertHasTransaction(m_CurTransaction);
    Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleTopLevelDecl);
    m_CurTransaction->append(DCI);
    if (!m_Consumer
        || getTransaction()->getIssuedDiags() == Transaction::kErrors)
      return true;

    if (comesFromASTReader(DGR)) {
      for (DeclGroupRef::iterator DI = DGR.begin(), DE = DGR.end();
           DI != DE; ++DI) {
        DeclGroupRef SplitDGR(*DI);
        // FIXME: The special namespace treatment (not sending itself to
        // CodeGen, but only its content - if the contained decl should be
        // emitted) works around issue with the static initialization when
        // having a PCH and loading a library. We don't want to generate
        // code for the static that will come through the library.
        //
        // This will be fixed with the clang::Modules. Make sure we remember.
        // assert(!getCI()->getLangOpts().Modules && "Please revisit!");
        if (NamespaceDecl* ND = dyn_cast<NamespaceDecl>(*DI)) {
          for (NamespaceDecl::decl_iterator NDI = ND->decls_begin(),
               EN = ND->decls_end(); NDI != EN; ++NDI) {
            // Recurse over decls inside the namespace, like
            // CodeGenModule::EmitNamespace() does.
            if (!shouldIgnore(*NDI))
              m_Consumer->HandleTopLevelDecl(DeclGroupRef(*NDI));
          }
        } else if (!shouldIgnore(*DI)) {
          m_Consumer->HandleTopLevelDecl(DeclGroupRef(*DI));
        }
        continue;
      }
    } else {
      m_Consumer->HandleTopLevelDecl(DGR);
    }
    return true;
  }

  void DeclCollector::HandleInterestingDecl(DeclGroupRef DGR) {
    assertHasTransaction(m_CurTransaction);
    Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleInterestingDecl);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DGR) || !shouldIgnore(*DGR.begin())))
      m_Consumer->HandleTopLevelDecl(DGR);
  }

  void DeclCollector::HandleTagDeclDefinition(TagDecl* TD) {
    assertHasTransaction(m_CurTransaction);
    Transaction::DelayCallInfo DCI(DeclGroupRef(TD),
                                   Transaction::kCCIHandleTagDeclDefinition);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(TD))
            || !shouldIgnore(TD)))
      m_Consumer->HandleTagDeclDefinition(TD);
  }

  void DeclCollector::HandleInvalidTagDeclDefinition(clang::TagDecl *TD){
    assertHasTransaction(m_CurTransaction);
    Transaction::DelayCallInfo DCI(DeclGroupRef(TD),
                                   Transaction::kCCIHandleTagDeclDefinition);
    m_CurTransaction->append(DCI);
    m_CurTransaction->setIssuedDiags(Transaction::kErrors);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(TD))
            || !shouldIgnore(TD)))
      m_Consumer->HandleInvalidTagDeclDefinition(TD);
  }

  void DeclCollector::HandleVTable(CXXRecordDecl* RD) {
    assertHasTransaction(m_CurTransaction);
    Transaction::DelayCallInfo DCI(DeclGroupRef(RD),
                                   Transaction::kCCIHandleVTable);
    m_CurTransaction->append(DCI);

    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(RD))
            || !shouldIgnore(RD)))
      m_Consumer->HandleVTable(RD);
    // Intentional no-op. It comes through Sema::DefineUsedVTables, which
    // comes either Sema::ActOnEndOfTranslationUnit or while instantiating a
    // template. In our case we will do it on transaction commit, without
    // keeping track of used vtables, because we have cases where we bypass the
    // clang/AST and directly ask the module so that we have to generate
    // everything without extra smartness.
  }

  void DeclCollector::CompleteTentativeDefinition(VarDecl* VD) {
    assertHasTransaction(m_CurTransaction);
    // C has tentative definitions which we might need to deal with when running
    // in C mode.
    Transaction::DelayCallInfo DCI(DeclGroupRef(VD),
                                   Transaction::kCCICompleteTentativeDefinition);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(VD))
            || !shouldIgnore(VD)))
    m_Consumer->CompleteTentativeDefinition(VD);
  }

  void DeclCollector::HandleTranslationUnit(ASTContext& Ctx) {
    //if (m_Consumer)
    //  m_Consumer->HandleTranslationUnit(Ctx);
  }

  void DeclCollector::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
    assertHasTransaction(m_CurTransaction);
    Transaction::DelayCallInfo DCI(DeclGroupRef(D),
                                   Transaction::kCCIHandleCXXImplicitFunctionInstantiation);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(D))
            || !shouldIgnore(D)))
    m_Consumer->HandleCXXImplicitFunctionInstantiation(D);
  }

  void DeclCollector::HandleCXXStaticMemberVarInstantiation(VarDecl *D) {
    assertHasTransaction(m_CurTransaction);
    Transaction::DelayCallInfo DCI(DeclGroupRef(D),
                                   Transaction::kCCIHandleCXXStaticMemberVarInstantiation);
    m_CurTransaction->append(DCI);
    if (m_Consumer
        && (!comesFromASTReader(DeclGroupRef(D))
            || !shouldIgnore(D)))
    m_Consumer->HandleCXXStaticMemberVarInstantiation(D);
  }

} // namespace cling
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commercial and non commercial
 * applications, as long as this copyright notice is maintained.
 *
 * This application 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.
 *
*/

#include <sstream>
#include <memory>

#include <osg/Notify>
#include <osg/NodeVisitor>
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>
#include <osgDB/ConvertUTF>

#include <OpenThreads/ScopedLock>

#include "ReaderWriterDAE.h"
#include "daeReader.h"
#include "daeWriter.h"

#ifdef WIN32
#include "windows.h"
#endif

#define SERIALIZER() OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex)

#if  __cplusplus > 199711L
    #define smart_ptr std::unique_ptr
#else
    #define smart_prt std::auto_ptr
#endif

osgDB::ReaderWriter::ReadResult
ReaderWriterDAE::readNode(std::istream& fin,
        const osgDB::ReaderWriter::Options* options) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    // Process options
    osgDAE::daeReader::Options pluginOptions;
    if( options )
    {
        pDAE = (DAE*)options->getPluginData("DAE");

        pluginOptions.precisionHint = options->getPrecisionHint();

        std::istringstream iss( options->getOptionString() );
        std::string opt;
        while (iss >> opt)
        {
            if( opt == "StrictTransparency") pluginOptions.strictTransparency = true;
            else if (opt == "daeTessellateNone") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_NONE;
            else if (opt == "daeTessellatePolygonsAsTriFans") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS_AS_TRIFAN;
            else if (opt == "daeTessellatePolygons") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS;
            else if (opt == "daeUsePredefinedTextureUnits") pluginOptions.usePredefinedTextureUnits = true;
            else if (opt == "daeUseSequencedTextureUnits") pluginOptions.usePredefinedTextureUnits = false;
        }
    }

    if (NULL == pDAE)
    {
        bOwnDAE = true;
#ifdef COLLADA_DOM_2_4_OR_LATER
        pDAE = new DAE(NULL,NULL,_specversion);
#else
        pDAE = new DAE;
#endif
    }

    smart_ptr<DAE> scopedDae(bOwnDAE ? pDAE : NULL);        // Deallocates locally created structure at scope exit

    osgDAE::daeReader daeReader(pDAE, &pluginOptions);

    if ( ! daeReader.convert( fin ) )
    {
        OSG_WARN << "Load failed in COLLADA DOM conversion" << std::endl;
        return ReadResult::ERROR_IN_READING_FILE;
    }

    if ( options )
    {
        // Return the document URI
        if (options->getPluginData("DAE-DocumentURI"))
            *(std::string*)options->getPluginData("DAE-DocumentURI") = std::string("/dev/null");
        // Return some additional information about the document
        if (options->getPluginData("DAE-AssetUnitName"))
             *(std::string*)options->getPluginData("DAE-AssetUnitName") = daeReader.getAssetUnitName();
        if (options->getPluginData("DAE-AssetUnitMeter"))
            *(float*)options->getPluginData("DAE-AssetUnitMeter") = daeReader.getAssetUnitMeter();
        if (options->getPluginData("DAE-AssetUp_axis"))
            *(domUpAxisType*)options->getPluginData("DAE-AssetUp_axis") = daeReader.getAssetUpAxis();
    }

    osg::Node* rootNode( daeReader.getRootNode() );
    return rootNode;
}

osgDB::ReaderWriter::ReadResult
ReaderWriterDAE::readNode(const std::string& fname,
        const osgDB::ReaderWriter::Options* options) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    // Process options
    osgDAE::daeReader::Options pluginOptions;
    if( options )
    {
        pDAE = (DAE*)options->getPluginData("DAE");

        pluginOptions.precisionHint = options->getPrecisionHint();

        std::istringstream iss( options->getOptionString() );
        std::string opt;
        while (iss >> opt)
        {
            if( opt == "StrictTransparency") pluginOptions.strictTransparency = true;
            else if (opt == "daeTessellateNone")              pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_NONE;
            else if (opt == "daeTessellatePolygonsAsTriFans") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS_AS_TRIFAN;
            else if (opt == "daeTessellatePolygons")          pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS;
            else if (opt == "daeUsePredefinedTextureUnits") pluginOptions.usePredefinedTextureUnits = true;
            else if (opt == "daeUseSequencedTextureUnits")  pluginOptions.usePredefinedTextureUnits = false;
        }
    }

    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
    if( ! acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED;

    std::string fileName( osgDB::findDataFile( fname, options ) );
    if( fileName.empty() ) return ReadResult::FILE_NOT_FOUND;

    OSG_INFO << "ReaderWriterDAE( \"" << fileName << "\" )" << std::endl;

    if (NULL == pDAE)
    {
        bOwnDAE = true;
#ifdef COLLADA_DOM_2_4_OR_LATER
        pDAE = new DAE(NULL,NULL,_specversion);
#else
        pDAE = new DAE;
#endif
    }

    smart_ptr<DAE> scopedDae(bOwnDAE ? pDAE : NULL);        // Deallocates locally created structure at scope exit

    osgDAE::daeReader daeReader(pDAE, &pluginOptions);

    // Convert file name to URI
    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fileName);

    if ( ! daeReader.convert( fileURI ) )
    {
        OSG_WARN << "Load failed in COLLADA DOM conversion" << std::endl;
        return ReadResult::ERROR_IN_READING_FILE;
    }

    if ( options )
    {
        // Return the document URI
        if (options->getPluginData("DAE-DocumentURI"))
            *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
        // Return some additional information about the document
        if (options->getPluginData("DAE-AssetUnitName"))
             *(std::string*)options->getPluginData("DAE-AssetUnitName") = daeReader.getAssetUnitName();
        if (options->getPluginData("DAE-AssetUnitMeter"))
            *(float*)options->getPluginData("DAE-AssetUnitMeter") = daeReader.getAssetUnitMeter();
        if (options->getPluginData("DAE-AssetUp_axis"))
            *(domUpAxisType*)options->getPluginData("DAE-AssetUp_axis") = daeReader.getAssetUpAxis();
    }

    osg::Node* rootNode( daeReader.getRootNode() );
    return rootNode;
}

///////////////////////////////////////////////////////////////////////////

osgDB::ReaderWriter::WriteResult
ReaderWriterDAE::writeNode( const osg::Node& node,
        const std::string& fname, const osgDB::ReaderWriter::Options* options ) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
    if( ! acceptsExtension(ext) ) return WriteResult::FILE_NOT_HANDLED;

    // Process options
    osgDAE::daeWriter::Options pluginOptions;
    std::string srcDirectory( osgDB::getFilePath(node.getName().empty() ? fname : node.getName()) );        // Base dir when relativising images paths
    if( options )
    {
        pDAE = (DAE*)options->getPluginData("DAE");

        const std::string & baseDir = options->getPluginStringData("baseImageDir");        // Rename "srcModelPath" (and call getFilePath() on it)?
        if (!baseDir.empty()) srcDirectory = baseDir;

        const std::string & relativiseImagesPathNbUpDirs = options->getPluginStringData("DAE-relativiseImagesPathNbUpDirs");
        if (!relativiseImagesPathNbUpDirs.empty()) {
            std::istringstream iss(relativiseImagesPathNbUpDirs);
            iss >> pluginOptions.relativiseImagesPathNbUpDirs;
        }

        // Sukender's note: I don't know why DAE seems to accept comma-sparated options instead of space-separated options as other ReaderWriters. However, to avoid breaking compatibility, here's a workaround:
        std::string optString( options->getOptionString() );
        for(std::string::iterator it=optString.begin(); it!=optString.end(); ++it) {
            if (*it == ' ') *it = ',';
        }
        std::istringstream iss( optString );
        std::string opt;

        //while (iss >> opt)
        while( std::getline( iss, opt, ',' ) )
        {
            if( opt == "polygon") pluginOptions.usePolygons = true;
            else if (opt == "GoogleMode") pluginOptions.googleMode = true;
            else if (opt == "NoExtras") pluginOptions.writeExtras = false;
            else if (opt == "daeEarthTex") pluginOptions.earthTex = true;
            else if (opt == "daeZUpAxis") {}    // Nothing (old option)
            else if (opt == "daeLinkOriginalTexturesNoForce") { pluginOptions.linkOrignialTextures = true; pluginOptions.forceTexture = false; }
            else if (opt == "daeLinkOriginalTexturesForce")   { pluginOptions.linkOrignialTextures = true; pluginOptions.forceTexture = true; }
            else if (opt == "daeNamesUseCodepage") pluginOptions.namesUseCodepage = true;
            else if (opt == "daeRenameIds") pluginOptions.renameIds = true;
            else if (!opt.empty())
            {
                OSG_NOTICE << std::endl << "COLLADA dae plugin: unrecognized option \"" << opt <<  std::endl;
            }
        }
    }

    if (NULL == pDAE)
    {
        bOwnDAE = true;
#ifdef COLLADA_DOM_2_4_OR_LATER
        pDAE = new DAE(NULL,NULL,_specversion);
#else
        pDAE = new DAE;
#endif
    }
    smart_ptr<DAE> scopedDae(bOwnDAE ? pDAE : NULL);        // Deallocates locally created structure at scope exit

    // Convert file name to URI
    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fname);

    osg::NodeVisitor::TraversalMode traversalMode = pluginOptions.writeExtras ? osg::NodeVisitor::TRAVERSE_ALL_CHILDREN : osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN;

    osgDAE::daeWriter daeWriter(pDAE, fileURI, osgDB::getFilePath(fname), srcDirectory, options, traversalMode, &pluginOptions);
    daeWriter.setRootNode( node );
    const_cast<osg::Node*>(&node)->accept( daeWriter );

    osgDB::ReaderWriter::WriteResult retVal( WriteResult::ERROR_IN_WRITING_FILE );
    if ( daeWriter.isSuccess() )
    {
        if (pDAE->write(fileURI))
            retVal = WriteResult::FILE_SAVED;
    }

    if ( options )
    {
        if (!bOwnDAE)
        {
            // Return the document URI used so that users of an external DAE object
            // can locate the correct database
            if (options->getPluginData("DAE-DocumentURI"))
                *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
        }
    }

    return retVal;
}

static void replace(std::string & str, const char from, const std::string & to)
{
    // Replace for all occurrences
    for(std::string::size_type pos=str.find(from); pos!=std::string::npos; pos=str.find(from))
    {
        str.replace(pos, 1, to);
    }
}

static void replace(std::string & str, const std::string & from, const std::string & to)
{
    // Replace for all occurrences
    std::size_t lenFrom = from.size();
    std::size_t lenTo = to.size();
    for(std::string::size_type pos=str.find(from); pos!=std::string::npos; pos = str.find(from, pos+lenTo))
    {
        str.replace(pos, lenFrom, to);
    }
}

std::string ReaderWriterDAE::ConvertFilePathToColladaCompatibleURI(const std::string& FilePath)
{
#ifdef OSG_USE_UTF8_FILENAME
    std::string path( cdom::nativePathToUri( FilePath ) );
#else
    std::string path( cdom::nativePathToUri( osgDB::convertStringFromCurrentCodePageToUTF8(FilePath) ) );
#endif

    // Unfortunately, cdom::nativePathToUri() does not convert '#' characters to "%23" as expected.
    // So having /a/#b/c will generate a wrong conversion, as '#' will be misinterpreted as an URI fragment.
    // Here are listed all special chars, but only # was found problematic. I (Sukender) tested #{}^~[]`;@=&$ under Windows.
    // Uncomment lines if you find issues with some other special characters.

    //replace(path, '%', "%25");        // % at first
    //replace(path, ' ', "%20");
    replace(path, '#', "%23");
    //replace(path, '<', "%3C");
    //replace(path, '>', "%3E");
    //replace(path, '{', "%7B");
    //replace(path, '}', "%7D");
    //replace(path, '|', "%7C");
    //replace(path, '^', "%5E");
    //replace(path, '~', "%7E");
    //replace(path, '[', "%5B");
    //replace(path, '}', "%5D");
    //replace(path, '`', "%60");
    //replace(path, ';', "%3B");
    //replace(path, '?', "%3F");
    //replace(path, '@', "%40");
    //replace(path, '=', "%3D");
    //replace(path, '&', "%26");
    //replace(path, '$', "%24");
    return path;
}

std::string ReaderWriterDAE::ConvertColladaCompatibleURIToFilePath(const std::string& uri)
{
    // Reciprocal of ConvertFilePathToColladaCompatibleURI()
#ifdef OSG_USE_UTF8_FILENAME
    std::string path( cdom::uriToNativePath( uri ) );
#else
    std::string path( osgDB::convertStringFromCurrentCodePageToUTF8( cdom::uriToNativePath(uri) ) );
#endif
    replace(path, "%23", "#");
    return path;
}

///////////////////////////////////////////////////////////////////////////
// Add ourself to the Registry to instantiate the reader/writer.

REGISTER_OSGPLUGIN(dae, ReaderWriterDAE)

// vim: set sw=4 ts=8 et ic ai:
<commit_msg>Fixed typo<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commercial and non commercial
 * applications, as long as this copyright notice is maintained.
 *
 * This application 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.
 *
*/

#include <sstream>
#include <memory>

#include <osg/Notify>
#include <osg/NodeVisitor>
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>
#include <osgDB/ConvertUTF>

#include <OpenThreads/ScopedLock>

#include "ReaderWriterDAE.h"
#include "daeReader.h"
#include "daeWriter.h"

#ifdef WIN32
#include "windows.h"
#endif

#define SERIALIZER() OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex)

#if  __cplusplus > 199711L
    #define smart_ptr std::unique_ptr
#else
    #define smart_ptr std::auto_ptr
#endif

osgDB::ReaderWriter::ReadResult
ReaderWriterDAE::readNode(std::istream& fin,
        const osgDB::ReaderWriter::Options* options) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    // Process options
    osgDAE::daeReader::Options pluginOptions;
    if( options )
    {
        pDAE = (DAE*)options->getPluginData("DAE");

        pluginOptions.precisionHint = options->getPrecisionHint();

        std::istringstream iss( options->getOptionString() );
        std::string opt;
        while (iss >> opt)
        {
            if( opt == "StrictTransparency") pluginOptions.strictTransparency = true;
            else if (opt == "daeTessellateNone") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_NONE;
            else if (opt == "daeTessellatePolygonsAsTriFans") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS_AS_TRIFAN;
            else if (opt == "daeTessellatePolygons") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS;
            else if (opt == "daeUsePredefinedTextureUnits") pluginOptions.usePredefinedTextureUnits = true;
            else if (opt == "daeUseSequencedTextureUnits") pluginOptions.usePredefinedTextureUnits = false;
        }
    }

    if (NULL == pDAE)
    {
        bOwnDAE = true;
#ifdef COLLADA_DOM_2_4_OR_LATER
        pDAE = new DAE(NULL,NULL,_specversion);
#else
        pDAE = new DAE;
#endif
    }

    smart_ptr<DAE> scopedDae(bOwnDAE ? pDAE : NULL);        // Deallocates locally created structure at scope exit

    osgDAE::daeReader daeReader(pDAE, &pluginOptions);

    if ( ! daeReader.convert( fin ) )
    {
        OSG_WARN << "Load failed in COLLADA DOM conversion" << std::endl;
        return ReadResult::ERROR_IN_READING_FILE;
    }

    if ( options )
    {
        // Return the document URI
        if (options->getPluginData("DAE-DocumentURI"))
            *(std::string*)options->getPluginData("DAE-DocumentURI") = std::string("/dev/null");
        // Return some additional information about the document
        if (options->getPluginData("DAE-AssetUnitName"))
             *(std::string*)options->getPluginData("DAE-AssetUnitName") = daeReader.getAssetUnitName();
        if (options->getPluginData("DAE-AssetUnitMeter"))
            *(float*)options->getPluginData("DAE-AssetUnitMeter") = daeReader.getAssetUnitMeter();
        if (options->getPluginData("DAE-AssetUp_axis"))
            *(domUpAxisType*)options->getPluginData("DAE-AssetUp_axis") = daeReader.getAssetUpAxis();
    }

    osg::Node* rootNode( daeReader.getRootNode() );
    return rootNode;
}

osgDB::ReaderWriter::ReadResult
ReaderWriterDAE::readNode(const std::string& fname,
        const osgDB::ReaderWriter::Options* options) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    // Process options
    osgDAE::daeReader::Options pluginOptions;
    if( options )
    {
        pDAE = (DAE*)options->getPluginData("DAE");

        pluginOptions.precisionHint = options->getPrecisionHint();

        std::istringstream iss( options->getOptionString() );
        std::string opt;
        while (iss >> opt)
        {
            if( opt == "StrictTransparency") pluginOptions.strictTransparency = true;
            else if (opt == "daeTessellateNone")              pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_NONE;
            else if (opt == "daeTessellatePolygonsAsTriFans") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS_AS_TRIFAN;
            else if (opt == "daeTessellatePolygons")          pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS;
            else if (opt == "daeUsePredefinedTextureUnits") pluginOptions.usePredefinedTextureUnits = true;
            else if (opt == "daeUseSequencedTextureUnits")  pluginOptions.usePredefinedTextureUnits = false;
        }
    }

    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
    if( ! acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED;

    std::string fileName( osgDB::findDataFile( fname, options ) );
    if( fileName.empty() ) return ReadResult::FILE_NOT_FOUND;

    OSG_INFO << "ReaderWriterDAE( \"" << fileName << "\" )" << std::endl;

    if (NULL == pDAE)
    {
        bOwnDAE = true;
#ifdef COLLADA_DOM_2_4_OR_LATER
        pDAE = new DAE(NULL,NULL,_specversion);
#else
        pDAE = new DAE;
#endif
    }

    smart_ptr<DAE> scopedDae(bOwnDAE ? pDAE : NULL);        // Deallocates locally created structure at scope exit

    osgDAE::daeReader daeReader(pDAE, &pluginOptions);

    // Convert file name to URI
    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fileName);

    if ( ! daeReader.convert( fileURI ) )
    {
        OSG_WARN << "Load failed in COLLADA DOM conversion" << std::endl;
        return ReadResult::ERROR_IN_READING_FILE;
    }

    if ( options )
    {
        // Return the document URI
        if (options->getPluginData("DAE-DocumentURI"))
            *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
        // Return some additional information about the document
        if (options->getPluginData("DAE-AssetUnitName"))
             *(std::string*)options->getPluginData("DAE-AssetUnitName") = daeReader.getAssetUnitName();
        if (options->getPluginData("DAE-AssetUnitMeter"))
            *(float*)options->getPluginData("DAE-AssetUnitMeter") = daeReader.getAssetUnitMeter();
        if (options->getPluginData("DAE-AssetUp_axis"))
            *(domUpAxisType*)options->getPluginData("DAE-AssetUp_axis") = daeReader.getAssetUpAxis();
    }

    osg::Node* rootNode( daeReader.getRootNode() );
    return rootNode;
}

///////////////////////////////////////////////////////////////////////////

osgDB::ReaderWriter::WriteResult
ReaderWriterDAE::writeNode( const osg::Node& node,
        const std::string& fname, const osgDB::ReaderWriter::Options* options ) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
    if( ! acceptsExtension(ext) ) return WriteResult::FILE_NOT_HANDLED;

    // Process options
    osgDAE::daeWriter::Options pluginOptions;
    std::string srcDirectory( osgDB::getFilePath(node.getName().empty() ? fname : node.getName()) );        // Base dir when relativising images paths
    if( options )
    {
        pDAE = (DAE*)options->getPluginData("DAE");

        const std::string & baseDir = options->getPluginStringData("baseImageDir");        // Rename "srcModelPath" (and call getFilePath() on it)?
        if (!baseDir.empty()) srcDirectory = baseDir;

        const std::string & relativiseImagesPathNbUpDirs = options->getPluginStringData("DAE-relativiseImagesPathNbUpDirs");
        if (!relativiseImagesPathNbUpDirs.empty()) {
            std::istringstream iss(relativiseImagesPathNbUpDirs);
            iss >> pluginOptions.relativiseImagesPathNbUpDirs;
        }

        // Sukender's note: I don't know why DAE seems to accept comma-sparated options instead of space-separated options as other ReaderWriters. However, to avoid breaking compatibility, here's a workaround:
        std::string optString( options->getOptionString() );
        for(std::string::iterator it=optString.begin(); it!=optString.end(); ++it) {
            if (*it == ' ') *it = ',';
        }
        std::istringstream iss( optString );
        std::string opt;

        //while (iss >> opt)
        while( std::getline( iss, opt, ',' ) )
        {
            if( opt == "polygon") pluginOptions.usePolygons = true;
            else if (opt == "GoogleMode") pluginOptions.googleMode = true;
            else if (opt == "NoExtras") pluginOptions.writeExtras = false;
            else if (opt == "daeEarthTex") pluginOptions.earthTex = true;
            else if (opt == "daeZUpAxis") {}    // Nothing (old option)
            else if (opt == "daeLinkOriginalTexturesNoForce") { pluginOptions.linkOrignialTextures = true; pluginOptions.forceTexture = false; }
            else if (opt == "daeLinkOriginalTexturesForce")   { pluginOptions.linkOrignialTextures = true; pluginOptions.forceTexture = true; }
            else if (opt == "daeNamesUseCodepage") pluginOptions.namesUseCodepage = true;
            else if (opt == "daeRenameIds") pluginOptions.renameIds = true;
            else if (!opt.empty())
            {
                OSG_NOTICE << std::endl << "COLLADA dae plugin: unrecognized option \"" << opt <<  std::endl;
            }
        }
    }

    if (NULL == pDAE)
    {
        bOwnDAE = true;
#ifdef COLLADA_DOM_2_4_OR_LATER
        pDAE = new DAE(NULL,NULL,_specversion);
#else
        pDAE = new DAE;
#endif
    }
    smart_ptr<DAE> scopedDae(bOwnDAE ? pDAE : NULL);        // Deallocates locally created structure at scope exit

    // Convert file name to URI
    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fname);

    osg::NodeVisitor::TraversalMode traversalMode = pluginOptions.writeExtras ? osg::NodeVisitor::TRAVERSE_ALL_CHILDREN : osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN;

    osgDAE::daeWriter daeWriter(pDAE, fileURI, osgDB::getFilePath(fname), srcDirectory, options, traversalMode, &pluginOptions);
    daeWriter.setRootNode( node );
    const_cast<osg::Node*>(&node)->accept( daeWriter );

    osgDB::ReaderWriter::WriteResult retVal( WriteResult::ERROR_IN_WRITING_FILE );
    if ( daeWriter.isSuccess() )
    {
        if (pDAE->write(fileURI))
            retVal = WriteResult::FILE_SAVED;
    }

    if ( options )
    {
        if (!bOwnDAE)
        {
            // Return the document URI used so that users of an external DAE object
            // can locate the correct database
            if (options->getPluginData("DAE-DocumentURI"))
                *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
        }
    }

    return retVal;
}

static void replace(std::string & str, const char from, const std::string & to)
{
    // Replace for all occurrences
    for(std::string::size_type pos=str.find(from); pos!=std::string::npos; pos=str.find(from))
    {
        str.replace(pos, 1, to);
    }
}

static void replace(std::string & str, const std::string & from, const std::string & to)
{
    // Replace for all occurrences
    std::size_t lenFrom = from.size();
    std::size_t lenTo = to.size();
    for(std::string::size_type pos=str.find(from); pos!=std::string::npos; pos = str.find(from, pos+lenTo))
    {
        str.replace(pos, lenFrom, to);
    }
}

std::string ReaderWriterDAE::ConvertFilePathToColladaCompatibleURI(const std::string& FilePath)
{
#ifdef OSG_USE_UTF8_FILENAME
    std::string path( cdom::nativePathToUri( FilePath ) );
#else
    std::string path( cdom::nativePathToUri( osgDB::convertStringFromCurrentCodePageToUTF8(FilePath) ) );
#endif

    // Unfortunately, cdom::nativePathToUri() does not convert '#' characters to "%23" as expected.
    // So having /a/#b/c will generate a wrong conversion, as '#' will be misinterpreted as an URI fragment.
    // Here are listed all special chars, but only # was found problematic. I (Sukender) tested #{}^~[]`;@=&$ under Windows.
    // Uncomment lines if you find issues with some other special characters.

    //replace(path, '%', "%25");        // % at first
    //replace(path, ' ', "%20");
    replace(path, '#', "%23");
    //replace(path, '<', "%3C");
    //replace(path, '>', "%3E");
    //replace(path, '{', "%7B");
    //replace(path, '}', "%7D");
    //replace(path, '|', "%7C");
    //replace(path, '^', "%5E");
    //replace(path, '~', "%7E");
    //replace(path, '[', "%5B");
    //replace(path, '}', "%5D");
    //replace(path, '`', "%60");
    //replace(path, ';', "%3B");
    //replace(path, '?', "%3F");
    //replace(path, '@', "%40");
    //replace(path, '=', "%3D");
    //replace(path, '&', "%26");
    //replace(path, '$', "%24");
    return path;
}

std::string ReaderWriterDAE::ConvertColladaCompatibleURIToFilePath(const std::string& uri)
{
    // Reciprocal of ConvertFilePathToColladaCompatibleURI()
#ifdef OSG_USE_UTF8_FILENAME
    std::string path( cdom::uriToNativePath( uri ) );
#else
    std::string path( osgDB::convertStringFromCurrentCodePageToUTF8( cdom::uriToNativePath(uri) ) );
#endif
    replace(path, "%23", "#");
    return path;
}

///////////////////////////////////////////////////////////////////////////
// Add ourself to the Registry to instantiate the reader/writer.

REGISTER_OSGPLUGIN(dae, ReaderWriterDAE)

// vim: set sw=4 ts=8 et ic ai:
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commercial and non commercial
 * applications, as long as this copyright notice is maintained.
 *
 * This application 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.
 *
*/

#include <sstream>
#include <memory>

#include <osg/Notify>
#include <osg/NodeVisitor>
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>

#include <OpenThreads/ScopedLock>

#include "ReaderWriterDAE.h"
#include "daeReader.h"
#include "daeWriter.h"

#ifdef WIN32
#include "windows.h"
#endif

#define SERIALIZER() OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex)

osgDB::ReaderWriter::ReadResult
ReaderWriterDAE::readNode(const std::string& fname,
        const osgDB::ReaderWriter::Options* options) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    if ( options )
        pDAE = (DAE*)options->getPluginData("DAE");

    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
    if( ! acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED;

    std::string fileName( osgDB::findDataFile( fname, options ) );
    if( fileName.empty() ) return ReadResult::FILE_NOT_FOUND;

    OSG_INFO << "ReaderWriterDAE( \"" << fileName << "\" )" << std::endl;

    if (NULL == pDAE)
    {
        bOwnDAE = true;
        pDAE = new DAE;
    }

    osgDAE::daeReader daeReader(pDAE, options && options->getOptionString().find("StrictTransparency") != std::string::npos ) ;

    // Convert file name to URI
    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fileName);

    if ( ! daeReader.convert( fileURI ) )
    {
        OSG_WARN << "Load failed in COLLADA DOM conversion" << std::endl;
        return ReadResult::ERROR_IN_READING_FILE;
    }

    if ( options )
    {
        // Return the document URI
        if (options->getPluginData("DAE-DocumentURI"))
            *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
        // Return some additional information about the document
        if (options->getPluginData("DAE-AssetUnitName"))
             *(std::string*)options->getPluginData("DAE-AssetUnitName") = daeReader.getAssetUnitName();
        if (options->getPluginData("DAE-AssetUnitMeter"))
            *(float*)options->getPluginData("DAE-AssetUnitMeter") = daeReader.getAssetUnitMeter();
        if (options->getPluginData("DAE-AssetUp_axis"))
            *(domUpAxisType*)options->getPluginData("DAE-AssetUp_axis") = daeReader.getAssetUpAxis();
    }

    if (bOwnDAE)
        delete pDAE;

    osg::Node* rootNode( daeReader.getRootNode() );
    return rootNode;
}

///////////////////////////////////////////////////////////////////////////

osgDB::ReaderWriter::WriteResult
ReaderWriterDAE::writeNode( const osg::Node& node,
        const std::string& fname, const osgDB::ReaderWriter::Options* options ) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
    if( ! acceptsExtension(ext) ) return WriteResult::FILE_NOT_HANDLED;

    // Process options
    bool usePolygon(false);   // Use plugin option "polygon" to enable
    bool googleMode(false);   // Use plugin option "GoogleMode" to enable
    bool writeExtras(true);   // Use plugin option "NoExtras" to disable
    bool earthTex(false);     // Use plugin option "DaeEarthTex" to enable
    bool zUpAxis(false);      // Use plugin option "ZUpAxis" to enable
    bool forceTexture(false); // Use plugin option "ForceTexture" to enable
    if( options )
    {
        pDAE = (DAE*)options->getPluginData("DAE");
        // Sukender's note: I don't know why DAE seems to accept comma-sparated options instead of space-separated options as other ReaderWriters. However, to avoid breaking compatibility, here's a workaround:
        std::string optString( options->getOptionString() );
        for(std::string::iterator it=optString.begin(); it!=optString.end(); ++it) {
            if (*it == ' ') *it = ',';
        }
        std::istringstream iss( optString );
        std::string opt;

        //while (iss >> opt)
        while( std::getline( iss, opt, ',' ) )
        {
            if( opt == "polygon")  usePolygon = true;
            else if (opt == "GoogleMode") googleMode = true;
            else if (opt == "NoExtras") writeExtras = false;
            else if (opt == "DaeEarthTex") earthTex = true;
            else if (opt == "ZUpAxis") zUpAxis = true;
            else if (opt == "ForceTexture") forceTexture = true;
            else if (!opt.empty())
            {
                OSG_NOTICE << std::endl << "COLLADA dae plugin: unrecognized option \"" << opt <<  std::endl;
            }
        }
    }

    if (NULL == pDAE)
    {
        bOwnDAE = true;
        pDAE = new DAE;
    }

    // Convert file name to URI
    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fname);

    osg::NodeVisitor::TraversalMode traversalMode = writeExtras ? osg::NodeVisitor::TRAVERSE_ALL_CHILDREN : osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN;

    osgDAE::daeWriter daeWriter(pDAE, fileURI, usePolygon, googleMode, traversalMode, writeExtras, earthTex, zUpAxis, forceTexture);
    daeWriter.setRootNode( node );
    const_cast<osg::Node*>(&node)->accept( daeWriter );

    osgDB::ReaderWriter::WriteResult retVal( WriteResult::ERROR_IN_WRITING_FILE );
    if ( daeWriter.isSuccess() )
    {
        if (pDAE->write(fileURI))
            retVal = WriteResult::FILE_SAVED;
    }

    if ( options )
    {
        if (!bOwnDAE)
        {
            // Return the document URI used so that users of an external DAE object
            // can locate the correct database
            if (options->getPluginData("DAE-DocumentURI"))
                *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
        }
    }

    if (bOwnDAE)
        delete pDAE;

    return retVal;
}

std::string ReaderWriterDAE::ConvertFilePathToColladaCompatibleURI(const std::string& FilePath)
{
    return cdom::nativePathToUri(FilePath);
}

///////////////////////////////////////////////////////////////////////////
// Add ourself to the Registry to instantiate the reader/writer.

REGISTER_OSGPLUGIN(dae, ReaderWriterDAE)

// vim: set sw=4 ts=8 et ic ai:
<commit_msg>From Sukender, "Fixed ReaderWriterDAE::ConvertFilePathToColladaCompatibleURI(): It now handles paths containing '#' character as expected."<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commercial and non commercial
 * applications, as long as this copyright notice is maintained.
 *
 * This application 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.
 *
*/

#include <sstream>
#include <memory>

#include <osg/Notify>
#include <osg/NodeVisitor>
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>

#include <OpenThreads/ScopedLock>

#include "ReaderWriterDAE.h"
#include "daeReader.h"
#include "daeWriter.h"

#ifdef WIN32
#include "windows.h"
#endif

#define SERIALIZER() OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex)

osgDB::ReaderWriter::ReadResult
ReaderWriterDAE::readNode(const std::string& fname,
        const osgDB::ReaderWriter::Options* options) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    if ( options )
        pDAE = (DAE*)options->getPluginData("DAE");

    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
    if( ! acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED;

    std::string fileName( osgDB::findDataFile( fname, options ) );
    if( fileName.empty() ) return ReadResult::FILE_NOT_FOUND;

    OSG_INFO << "ReaderWriterDAE( \"" << fileName << "\" )" << std::endl;

    if (NULL == pDAE)
    {
        bOwnDAE = true;
        pDAE = new DAE;
    }

    osgDAE::daeReader daeReader(pDAE, options && options->getOptionString().find("StrictTransparency") != std::string::npos ) ;

    // Convert file name to URI
    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fileName);

    if ( ! daeReader.convert( fileURI ) )
    {
        OSG_WARN << "Load failed in COLLADA DOM conversion" << std::endl;
        return ReadResult::ERROR_IN_READING_FILE;
    }

    if ( options )
    {
        // Return the document URI
        if (options->getPluginData("DAE-DocumentURI"))
            *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
        // Return some additional information about the document
        if (options->getPluginData("DAE-AssetUnitName"))
             *(std::string*)options->getPluginData("DAE-AssetUnitName") = daeReader.getAssetUnitName();
        if (options->getPluginData("DAE-AssetUnitMeter"))
            *(float*)options->getPluginData("DAE-AssetUnitMeter") = daeReader.getAssetUnitMeter();
        if (options->getPluginData("DAE-AssetUp_axis"))
            *(domUpAxisType*)options->getPluginData("DAE-AssetUp_axis") = daeReader.getAssetUpAxis();
    }

    if (bOwnDAE)
        delete pDAE;

    osg::Node* rootNode( daeReader.getRootNode() );
    return rootNode;
}

///////////////////////////////////////////////////////////////////////////

osgDB::ReaderWriter::WriteResult
ReaderWriterDAE::writeNode( const osg::Node& node,
        const std::string& fname, const osgDB::ReaderWriter::Options* options ) const
{
    SERIALIZER();

    bool bOwnDAE = false;
    DAE* pDAE = NULL;

    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
    if( ! acceptsExtension(ext) ) return WriteResult::FILE_NOT_HANDLED;

    // Process options
    bool usePolygon(false);   // Use plugin option "polygon" to enable
    bool googleMode(false);   // Use plugin option "GoogleMode" to enable
    bool writeExtras(true);   // Use plugin option "NoExtras" to disable
    bool earthTex(false);     // Use plugin option "DaeEarthTex" to enable
    bool zUpAxis(false);      // Use plugin option "ZUpAxis" to enable
    bool forceTexture(false); // Use plugin option "ForceTexture" to enable
    if( options )
    {
        pDAE = (DAE*)options->getPluginData("DAE");
        // Sukender's note: I don't know why DAE seems to accept comma-sparated options instead of space-separated options as other ReaderWriters. However, to avoid breaking compatibility, here's a workaround:
        std::string optString( options->getOptionString() );
        for(std::string::iterator it=optString.begin(); it!=optString.end(); ++it) {
            if (*it == ' ') *it = ',';
        }
        std::istringstream iss( optString );
        std::string opt;

        //while (iss >> opt)
        while( std::getline( iss, opt, ',' ) )
        {
            if( opt == "polygon")  usePolygon = true;
            else if (opt == "GoogleMode") googleMode = true;
            else if (opt == "NoExtras") writeExtras = false;
            else if (opt == "DaeEarthTex") earthTex = true;
            else if (opt == "ZUpAxis") zUpAxis = true;
            else if (opt == "ForceTexture") forceTexture = true;
            else if (!opt.empty())
            {
                OSG_NOTICE << std::endl << "COLLADA dae plugin: unrecognized option \"" << opt <<  std::endl;
            }
        }
    }

    if (NULL == pDAE)
    {
        bOwnDAE = true;
        pDAE = new DAE;
    }

    // Convert file name to URI
    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fname);

    osg::NodeVisitor::TraversalMode traversalMode = writeExtras ? osg::NodeVisitor::TRAVERSE_ALL_CHILDREN : osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN;

    osgDAE::daeWriter daeWriter(pDAE, fileURI, usePolygon, googleMode, traversalMode, writeExtras, earthTex, zUpAxis, forceTexture);
    daeWriter.setRootNode( node );
    const_cast<osg::Node*>(&node)->accept( daeWriter );

    osgDB::ReaderWriter::WriteResult retVal( WriteResult::ERROR_IN_WRITING_FILE );
    if ( daeWriter.isSuccess() )
    {
        if (pDAE->write(fileURI))
            retVal = WriteResult::FILE_SAVED;
    }

    if ( options )
    {
        if (!bOwnDAE)
        {
            // Return the document URI used so that users of an external DAE object
            // can locate the correct database
            if (options->getPluginData("DAE-DocumentURI"))
                *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
        }
    }

    if (bOwnDAE)
        delete pDAE;

    return retVal;
}

static void replace(std::string & str, const char from, const std::string & to) {
    // Replace for all occurences
    for(std::string::size_type pos=str.find(from); pos!=std::string::npos; pos=str.find(from))
    {
        str.replace(pos, 1, to);
    }
}

std::string ReaderWriterDAE::ConvertFilePathToColladaCompatibleURI(const std::string& FilePath)
{
    std::string path( cdom::nativePathToUri(FilePath) );

    // Unfortunately, cdom::nativePathToUri() does not convert '#' characters to "%23" as expected.
    // So having /a/#b/c will generate a wrong conversion, as '#' will be misinterpreted as an URI fragment.
    // Here are listed all special chars, but only # was found problematic. I (Sukender) tested #{}^~[]`;@=&$ under Windows.
    // Uncomment lines if you find issues with some other special characters.

    //replace(path, '%', "%25");        // % at first
    //replace(path, ' ', "%20");
    replace(path, '#', "%23");
    //replace(path, '<', "%3C");
    //replace(path, '>', "%3E");
    //replace(path, '{', "%7B");
    //replace(path, '}', "%7D");
    //replace(path, '|', "%7C");
    //replace(path, '^', "%5E");
    //replace(path, '~', "%7E");
    //replace(path, '[', "%5B");
    //replace(path, '}', "%5D");
    //replace(path, '`', "%60");
    //replace(path, ';', "%3B");
    //replace(path, '?', "%3F");
    //replace(path, '@', "%40");
    //replace(path, '=', "%3D");
    //replace(path, '&', "%26");
    //replace(path, '$', "%24");
    return path;
}

///////////////////////////////////////////////////////////////////////////
// Add ourself to the Registry to instantiate the reader/writer.

REGISTER_OSGPLUGIN(dae, ReaderWriterDAE)

// vim: set sw=4 ts=8 et ic ai:
<|endoftext|>


<commit_before>#include "MatrixTransform.h"
#include "Group.h"

#include <osg/Notify>

#include <osgDB/FileNameUtils>
#include <osgDB/Registry>

using namespace osg;
using namespace osgDB;

class IVEReaderWriter : public ReaderWriter
{
    public:
        virtual const char* className() { return "IVE Reader/Writer"; }

        virtual bool acceptsExtension(const std::string& extension)
        {
            return equalCaseInsensitive(extension,"ive");
        }

        virtual ReadResult readNode(const std::string& fileName, const Options* options)
        {
            std::string ext = getFileExtension(fileName);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
            return readNode(istream,options);
        }

        virtual ReadResult readNode(std::istream& fin, const Options*)
        {
	    try{
                // Create datainputstream.
                ive::DataInputStream in(&fin);

                return in.readNode();
	    }
	    catch(ive::Exception e)
            {
	        std::cout<<"Error reading file: "<< e.getError()<<std::endl;
	        return ReadResult::FILE_NOT_HANDLED;
	    }
            return 0;
        }

        virtual WriteResult writeNode(const Node& node,const std::string& fileName, const osgDB::ReaderWriter::Options* options)
        {
            std::string ext = getFileExtension(fileName);
            if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;

            std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
            WriteResult result = writeNode(node, fout, options);
            fout.close();
            return result;
        }

        virtual WriteResult writeNode(const Node& node,std::ostream& fout, const osgDB::ReaderWriter::Options*)
        {
            try
            {
                ive::DataOutputStream out(&fout);

                out.writeNode(const_cast<osg::Node*>(&node));
                return WriteResult::FILE_SAVED;
            }
            catch(ive::Exception e)
            {
	        osg::notify(osg::WARN)<<"Error parsing OSG file: "<< e.getError() << std::endl;
            }
            return WriteResult::FILE_NOT_HANDLED;

        }

};

// now register with Registry to instantiate the above
// reader/writer.
RegisterReaderWriterProxy<IVEReaderWriter> g_IVEReaderWriterProxy;
<commit_msg>Added #ifdef IVE_CATCH_EXCEPTIONS to allow catching of exceptions to be turned off for debugging purposes.<commit_after>#include "MatrixTransform.h"
#include "Group.h"

#include <osg/Notify>

#include <osgDB/FileNameUtils>
#include <osgDB/Registry>

using namespace osg;
using namespace osgDB;

class IVEReaderWriter : public ReaderWriter
{
    public:
        virtual const char* className() { return "IVE Reader/Writer"; }

        virtual bool acceptsExtension(const std::string& extension)
        {
            return equalCaseInsensitive(extension,"ive");
        }

        virtual ReadResult readNode(const std::string& fileName, const Options* options)
        {
            std::string ext = getFileExtension(fileName);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
            return readNode(istream,options);
        }

        virtual ReadResult readNode(std::istream& fin, const Options*)
        {
        #define IVE_CATCH_EXCEPTIONS
        #ifdef IVE_CATCH_EXCEPTIONS
	    try{
        #endif
                // Create datainputstream.
                ive::DataInputStream in(&fin);

                return in.readNode();
        #ifdef IVE_CATCH_EXCEPTIONS
	    }
	    catch(ive::Exception e)
            {
	        std::cout<<"Error reading file: "<< e.getError()<<std::endl;
	        return ReadResult::FILE_NOT_HANDLED;
	    }
            return 0;
        #endif
        }

        virtual WriteResult writeNode(const Node& node,const std::string& fileName, const osgDB::ReaderWriter::Options* options)
        {
            std::string ext = getFileExtension(fileName);
            if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;

            std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
            WriteResult result = writeNode(node, fout, options);
            fout.close();
            return result;
        }

        virtual WriteResult writeNode(const Node& node,std::ostream& fout, const osgDB::ReaderWriter::Options*)
        {
            try
            {
                ive::DataOutputStream out(&fout);

                out.writeNode(const_cast<osg::Node*>(&node));
                return WriteResult::FILE_SAVED;
            }
            catch(ive::Exception e)
            {
	        osg::notify(osg::WARN)<<"Error parsing OSG file: "<< e.getError() << std::endl;
            }
            return WriteResult::FILE_NOT_HANDLED;

        }

};

// now register with Registry to instantiate the above
// reader/writer.
RegisterReaderWriterProxy<IVEReaderWriter> g_IVEReaderWriterProxy;
<|endoftext|>