<commit_before>/***************************************************************************
 *   Copyright (C) 2015 Alexander Golubev (Fat-Zer) <fatzer2@gmail.com>    *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#include <vector>
#include <list>
#include <set>
#include <boost/bind.hpp>
#include <QMessageBox>
#include <QPushButton>
#endif

#include <Base/Exception.h>
#include <App/Application.h>
#include <App/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/Command.h>
#include <Gui/Application.h>
#include <Mod/PartDesign/App/Body.h>
#include <Mod/PartDesign/App/Feature.h>
#include "WorkflowManager.h"

using namespace PartDesignGui;

WorkflowManager * WorkflowManager::_instance = nullptr;

WorkflowManager::WorkflowManager() {
    // Fill the map with already opened documents
   for ( auto doc : App::GetApplication().getDocuments() ) {
        slotFinishRestoreDocument ( *doc );
   }

    connectNewDocument = App::GetApplication().signalNewDocument.connect(
            boost::bind( &WorkflowManager::slotNewDocument, this, _1 ) );
    connectFinishRestoreDocument = App::GetApplication().signalFinishRestoreDocument.connect(
            boost::bind( &WorkflowManager::slotFinishRestoreDocument, this, _1 ) );
    connectDeleteDocument = App::GetApplication().signalDeleteDocument.connect(
            boost::bind( &WorkflowManager::slotDeleteDocument, this, _1 ) );
}

WorkflowManager::~WorkflowManager() {
    // they won't be automatically disconnected on destruction!
    connectNewDocument.disconnect ();
    connectFinishRestoreDocument.disconnect ();
    connectDeleteDocument.disconnect ();
}

// Those destruction/construction is not really needed and could be done in the instance()
// but to make things a bit more clear, better to keep them around.
void WorkflowManager::init() {
    if (!_instance) {
        _instance = new WorkflowManager();
    } else {
        //throw Base::Exception( "Trying to init the workflow manager second time." );
    }
}

WorkflowManager *WorkflowManager::instance() {
    if (!_instance) {
        WorkflowManager::init();
    }
    return _instance;
}

void WorkflowManager::destruct() {
    if (_instance) {
        delete _instance;
        _instance = nullptr;
    }
}

void WorkflowManager::slotNewDocument( const App::Document &doc ) {
    // new document always uses new workflow
    dwMap[&doc] = Workflow::Modern;
}

void WorkflowManager::slotFinishRestoreDocument( const App::Document &doc ) {
    Workflow wf = guessWorkflow (&doc);
    // Mark document as undetermined if the guessed workflow is not new
    if( wf != Workflow::Modern ) {
        wf = Workflow::Undetermined;
    }
    dwMap[&doc] = wf;
}

void WorkflowManager::slotDeleteDocument( const App::Document &doc ) {
    dwMap.erase(&doc);
}

Workflow WorkflowManager::getWorkflowForDocument( App::Document *doc) {
    assert (doc);

    auto it = dwMap.find(doc);

    if ( it!=dwMap.end() ) {
        return it->second;
    } else {
        // We haven't yet checked the file workflow
        // May happen if e.g. file not completely loaded yet
        return Workflow::Undetermined;
    }
}

Workflow WorkflowManager::determineWorkflow(App::Document *doc) {
    Workflow rv = getWorkflowForDocument (doc);

    if (rv != Workflow::Undetermined) {
        // Return if workflow is known
        return rv;
    }

    // Guess the workflow again
    rv = guessWorkflow (doc);
    if (rv != Workflow::Modern) {
        QMessageBox msgBox(Gui::getMainWindow());

        if ( rv == Workflow::Legacy ) { // legacy messages
            msgBox.setText( QObject::tr( "The document \"%1\" you are editing was designed with an old version of "
                            "PartDesign workbench." ).arg( QString::fromStdString ( doc->getName()) ) );
            msgBox.setInformativeText (
                    QObject::tr( "Do you want to migrate in order to use modern PartDesign features?" ) );
        }
        else { // The document is already in the middle of migration
            msgBox.setText( QObject::tr( "The document \"%1\" seems to be either in the middle of"
                        " the migration process from legacy PartDesign or have a slightly broken structure."
                        ).arg( QString::fromStdString ( doc->getName()) ) );
            msgBox.setInformativeText (
                    QObject::tr( "Do you want to make the migration automatically?" ) );
        }
        msgBox.setDetailedText( QObject::tr( "Note: If you choose to migrate you won't be able to edit"
                    " the file with an old FreeCAD versions.\n"
                    "If you refuse to migrate you won't be able to use new PartDesign features"
                    " like Bodies and Parts. As a result you also won't be able to use your parts"
                    " in the assembly workbench.\n"
                    "Although you will be able to migrate any moment later with 'Part Design->Migrate...'." ) );
        msgBox.setIcon( QMessageBox::Question );
        QPushButton * yesBtn      = msgBox.addButton ( QMessageBox::Yes );
        QPushButton * manuallyBtn = msgBox.addButton (
                QObject::tr ( "Migrate manually" ), QMessageBox::YesRole );

        // If it is already a document in the middle of the migration the user shouldn't refuse to migrate
        if ( rv != Workflow::Undetermined ) {
            msgBox.addButton ( QMessageBox::No  );
        }
        msgBox.setDefaultButton ( yesBtn );
        // TODO: Add some description of manual migration mode (2015-08-09, Fat-Zer)

        msgBox.exec();

        if ( msgBox.clickedButton() == yesBtn ) {
            Gui::Application::Instance->commandManager().runCommandByName("PartDesign_Migrate");
            rv = Workflow::Modern;
        } else if ( msgBox.clickedButton() == manuallyBtn ) {
            rv = Workflow::Undetermined;
        } else {
            rv = Workflow::Legacy;
        }
    }

    // Actually set the result in our map
    dwMap[ doc ] = rv;

    return rv;
}

void WorkflowManager::forceWorkflow(const App::Document *doc, Workflow wf) {
    dwMap[ doc ] = wf;
}

Workflow WorkflowManager::guessWorkflow(const App::Document *doc) {
    // Retrieve bodies of the document
    auto features = doc->getObjectsOfType( PartDesign::Feature::getClassTypeId() );

    if( features.empty() ) {
        // a new file should be done in the new workflow
        return Workflow::Modern;
    } else {
        auto bodies = doc->getObjectsOfType( PartDesign::Body::getClassTypeId() );
        if (bodies.empty()) {
            // If there are no bodies workflow is legacy
            return Workflow::Legacy;
        } else {
            bool features_without_bodies = false;

            for( auto feat: features ) {
                if( !PartDesign::Body::findBodyOf( feat ) ) {
                    features_without_bodies = true;
                    break;
                }
            }
            // if there are features not belonging to any body it means that migration was incomplete, otherwise it's Modern
            return features_without_bodies ? Workflow::Undetermined : Workflow::Modern;
        }
    }
}
<commit_msg>[For v0.18]PartDesign: translation fixes<commit_after>/***************************************************************************
 *   Copyright (C) 2015 Alexander Golubev (Fat-Zer) <fatzer2@gmail.com>    *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#include <vector>
#include <list>
#include <set>
#include <boost/bind.hpp>
#include <QMessageBox>
#include <QPushButton>
#endif

#include <Base/Exception.h>
#include <App/Application.h>
#include <App/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/Command.h>
#include <Gui/Application.h>
#include <Mod/PartDesign/App/Body.h>
#include <Mod/PartDesign/App/Feature.h>
#include "WorkflowManager.h"

using namespace PartDesignGui;

WorkflowManager * WorkflowManager::_instance = nullptr;

WorkflowManager::WorkflowManager() {
    // Fill the map with already opened documents
   for ( auto doc : App::GetApplication().getDocuments() ) {
        slotFinishRestoreDocument ( *doc );
   }

    connectNewDocument = App::GetApplication().signalNewDocument.connect(
            boost::bind( &WorkflowManager::slotNewDocument, this, _1 ) );
    connectFinishRestoreDocument = App::GetApplication().signalFinishRestoreDocument.connect(
            boost::bind( &WorkflowManager::slotFinishRestoreDocument, this, _1 ) );
    connectDeleteDocument = App::GetApplication().signalDeleteDocument.connect(
            boost::bind( &WorkflowManager::slotDeleteDocument, this, _1 ) );
}

WorkflowManager::~WorkflowManager() {
    // they won't be automatically disconnected on destruction!
    connectNewDocument.disconnect ();
    connectFinishRestoreDocument.disconnect ();
    connectDeleteDocument.disconnect ();
}

// Those destruction/construction is not really needed and could be done in the instance()
// but to make things a bit more clear, better to keep them around.
void WorkflowManager::init() {
    if (!_instance) {
        _instance = new WorkflowManager();
    } else {
        //throw Base::Exception( "Trying to init the workflow manager second time." );
    }
}

WorkflowManager *WorkflowManager::instance() {
    if (!_instance) {
        WorkflowManager::init();
    }
    return _instance;
}

void WorkflowManager::destruct() {
    if (_instance) {
        delete _instance;
        _instance = nullptr;
    }
}

void WorkflowManager::slotNewDocument( const App::Document &doc ) {
    // new document always uses new workflow
    dwMap[&doc] = Workflow::Modern;
}

void WorkflowManager::slotFinishRestoreDocument( const App::Document &doc ) {
    Workflow wf = guessWorkflow (&doc);
    // Mark document as undetermined if the guessed workflow is not new
    if( wf != Workflow::Modern ) {
        wf = Workflow::Undetermined;
    }
    dwMap[&doc] = wf;
}

void WorkflowManager::slotDeleteDocument( const App::Document &doc ) {
    dwMap.erase(&doc);
}

Workflow WorkflowManager::getWorkflowForDocument( App::Document *doc) {
    assert (doc);

    auto it = dwMap.find(doc);

    if ( it!=dwMap.end() ) {
        return it->second;
    } else {
        // We haven't yet checked the file workflow
        // May happen if e.g. file not completely loaded yet
        return Workflow::Undetermined;
    }
}

Workflow WorkflowManager::determineWorkflow(App::Document *doc) {
    Workflow rv = getWorkflowForDocument (doc);

    if (rv != Workflow::Undetermined) {
        // Return if workflow is known
        return rv;
    }

    // Guess the workflow again
    rv = guessWorkflow (doc);
    if (rv != Workflow::Modern) {
        QMessageBox msgBox(Gui::getMainWindow());

        if ( rv == Workflow::Legacy ) { // legacy messages
            msgBox.setText( QObject::tr( "The document \"%1\" you are editing was designed with an old version of "
                            "PartDesign workbench." ).arg( QString::fromStdString ( doc->getName()) ) );
            msgBox.setInformativeText (
                    QObject::tr( "Do you want to migrate in order to use modern PartDesign features?" ) );
        }
        else { // The document is already in the middle of migration
            msgBox.setText( QObject::tr( "The document \"%1\" seems to be either in the middle of"
                        " the migration process from legacy PartDesign or have a slightly broken structure."
                        ).arg( QString::fromStdString ( doc->getName()) ) );
            msgBox.setInformativeText (
                    QObject::tr( "Do you want to make the migration automatically?" ) );
        }
        msgBox.setDetailedText( QObject::tr( "Note: If you choose to migrate you won't be able to edit"
                    " the file with an older FreeCAD version.\n"
                    "If you refuse to migrate you won't be able to use new PartDesign features"
                    " like Bodies and Parts. As a result you also won't be able to use your parts"
                    " in the assembly workbench.\n"
                    "Although you will be able to migrate any moment later with 'Part Design->Migrate...'." ) );
        msgBox.setIcon( QMessageBox::Question );
        QPushButton * yesBtn      = msgBox.addButton ( QMessageBox::Yes );
        QPushButton * manuallyBtn = msgBox.addButton (
                QObject::tr ( "Migrate manually" ), QMessageBox::YesRole );

        // If it is already a document in the middle of the migration the user shouldn't refuse to migrate
        if ( rv != Workflow::Undetermined ) {
            msgBox.addButton ( QMessageBox::No  );
        }
        msgBox.setDefaultButton ( yesBtn );
        // TODO: Add some description of manual migration mode (2015-08-09, Fat-Zer)

        msgBox.exec();

        if ( msgBox.clickedButton() == yesBtn ) {
            Gui::Application::Instance->commandManager().runCommandByName("PartDesign_Migrate");
            rv = Workflow::Modern;
        } else if ( msgBox.clickedButton() == manuallyBtn ) {
            rv = Workflow::Undetermined;
        } else {
            rv = Workflow::Legacy;
        }
    }

    // Actually set the result in our map
    dwMap[ doc ] = rv;

    return rv;
}

void WorkflowManager::forceWorkflow(const App::Document *doc, Workflow wf) {
    dwMap[ doc ] = wf;
}

Workflow WorkflowManager::guessWorkflow(const App::Document *doc) {
    // Retrieve bodies of the document
    auto features = doc->getObjectsOfType( PartDesign::Feature::getClassTypeId() );

    if( features.empty() ) {
        // a new file should be done in the new workflow
        return Workflow::Modern;
    } else {
        auto bodies = doc->getObjectsOfType( PartDesign::Body::getClassTypeId() );
        if (bodies.empty()) {
            // If there are no bodies workflow is legacy
            return Workflow::Legacy;
        } else {
            bool features_without_bodies = false;

            for( auto feat: features ) {
                if( !PartDesign::Body::findBodyOf( feat ) ) {
                    features_without_bodies = true;
                    break;
                }
            }
            // if there are features not belonging to any body it means that migration was incomplete, otherwise it's Modern
            return features_without_bodies ? Workflow::Undetermined : Workflow::Modern;
        }
    }
}
<|endoftext|>


<commit_before>/*
 * This source file is part of MyGUI. For the latest info, see http://mygui.info/
 * Distributed under the MIT License
 * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
 */

#include "MyGUI_Precompiled.h"
#include "MyGUI_ResourceManualFont.h"
#include "MyGUI_SkinManager.h"
#include "MyGUI_RenderManager.h"
#include "MyGUI_TextureUtility.h"

namespace MyGUI
{

	ResourceManualFont::ResourceManualFont() :
		mDefaultHeight(0),
		mSubstituteGlyphInfo(nullptr),
		mTexture(nullptr)
	{
	}

	ResourceManualFont::~ResourceManualFont()
	{
	}

	GlyphInfo* ResourceManualFont::getGlyphInfo(Char _id)
	{
		CharMap::iterator iter = mCharMap.find(_id);

		if (iter != mCharMap.end())
			return &iter->second;

		return mSubstituteGlyphInfo;
	}

	void ResourceManualFont::loadTexture()
	{
		if (mTexture == nullptr)
		{
			RenderManager& render = RenderManager::getInstance();
			mTexture = render.getTexture(mSource);
			if (mTexture == nullptr)
			{
				mTexture = render.createTexture(mSource);
				if (mTexture != nullptr)
					mTexture->loadFromFile(mSource);
			}
		}
	}

	void ResourceManualFont::deserialization(xml::ElementPtr _node, Version _version)
	{
		Base::deserialization(_node, _version);

		xml::ElementEnumerator node = _node->getElementEnumerator();
		while (node.next())
		{
			if (node->getName() == "Property")
			{
				const std::string& key = node->findAttribute("key");
				const std::string& value = node->findAttribute("value");
				if (key == "Source") mSource = value;
				else if (key == "DefaultHeight") mDefaultHeight = utility::parseInt(value);
			}
		}

		loadTexture();

		if (mTexture != nullptr)
		{
			int textureWidth = mTexture->getWidth();
			int textureHeight = mTexture->getHeight();

			node = _node->getElementEnumerator();
			while (node.next())
			{
				if (node->getName() == "Codes")
				{
					xml::ElementEnumerator element = node->getElementEnumerator();
					while (element.next("Code"))
					{
						std::string value;
						// описане глифов
						if (element->findAttribute("index", value))
						{
							Char id = 0;
							if (value == "cursor")
								id = static_cast<Char>(FontCodeType::Cursor);
							else if (value == "selected")
								id = static_cast<Char>(FontCodeType::Selected);
							else if (value == "selected_back")
								id = static_cast<Char>(FontCodeType::SelectedBack);
							else if (value == "substitute")
								id = static_cast<Char>(FontCodeType::NotDefined);
							else
								id = utility::parseUInt(value);

							float advance(utility::parseValue<float>(element->findAttribute("advance")));
							FloatPoint bearing(utility::parseValue<FloatPoint>(element->findAttribute("bearing")));

							// texture coordinates
							FloatCoord coord(utility::parseValue<FloatCoord>(element->findAttribute("coord")));

							// glyph size, default to texture coordinate size
							std::string sizeString;
							IntSize size (coord.width, coord.height);
							if (element->findAttribute("size", sizeString))
							{
								size = utility::parseValue<IntSize>(sizeString);
							}

							if (advance == 0.0f)
								advance = size.width;

							GlyphInfo& glyphInfo = mCharMap.insert(CharMap::value_type(id, GlyphInfo(
								id,
								size.width,
								size.height,
								advance,
								bearing.left,
								bearing.top,
								FloatRect(
									coord.left / textureWidth,
									coord.top / textureHeight,
									coord.right() / textureWidth,
									coord.bottom() / textureHeight)
								))).first->second;

							if (id == FontCodeType::NotDefined)
								mSubstituteGlyphInfo = &glyphInfo;
						}
					}
				}
			}
		}
	}

	ITexture* ResourceManualFont::getTextureFont()
	{
		return mTexture;
	}

	int ResourceManualFont::getDefaultHeight()
	{
		return mDefaultHeight;
	}

} // namespace MyGUI
<commit_msg>use FloatSize instead of IntSize for ResourceManualFont "size" property<commit_after>/*
 * This source file is part of MyGUI. For the latest info, see http://mygui.info/
 * Distributed under the MIT License
 * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
 */

#include "MyGUI_Precompiled.h"
#include "MyGUI_ResourceManualFont.h"
#include "MyGUI_SkinManager.h"
#include "MyGUI_RenderManager.h"
#include "MyGUI_TextureUtility.h"

namespace MyGUI
{

	ResourceManualFont::ResourceManualFont() :
		mDefaultHeight(0),
		mSubstituteGlyphInfo(nullptr),
		mTexture(nullptr)
	{
	}

	ResourceManualFont::~ResourceManualFont()
	{
	}

	GlyphInfo* ResourceManualFont::getGlyphInfo(Char _id)
	{
		CharMap::iterator iter = mCharMap.find(_id);

		if (iter != mCharMap.end())
			return &iter->second;

		return mSubstituteGlyphInfo;
	}

	void ResourceManualFont::loadTexture()
	{
		if (mTexture == nullptr)
		{
			RenderManager& render = RenderManager::getInstance();
			mTexture = render.getTexture(mSource);
			if (mTexture == nullptr)
			{
				mTexture = render.createTexture(mSource);
				if (mTexture != nullptr)
					mTexture->loadFromFile(mSource);
			}
		}
	}

	void ResourceManualFont::deserialization(xml::ElementPtr _node, Version _version)
	{
		Base::deserialization(_node, _version);

		xml::ElementEnumerator node = _node->getElementEnumerator();
		while (node.next())
		{
			if (node->getName() == "Property")
			{
				const std::string& key = node->findAttribute("key");
				const std::string& value = node->findAttribute("value");
				if (key == "Source") mSource = value;
				else if (key == "DefaultHeight") mDefaultHeight = utility::parseInt(value);
			}
		}

		loadTexture();

		if (mTexture != nullptr)
		{
			int textureWidth = mTexture->getWidth();
			int textureHeight = mTexture->getHeight();

			node = _node->getElementEnumerator();
			while (node.next())
			{
				if (node->getName() == "Codes")
				{
					xml::ElementEnumerator element = node->getElementEnumerator();
					while (element.next("Code"))
					{
						std::string value;
						// описане глифов
						if (element->findAttribute("index", value))
						{
							Char id = 0;
							if (value == "cursor")
								id = static_cast<Char>(FontCodeType::Cursor);
							else if (value == "selected")
								id = static_cast<Char>(FontCodeType::Selected);
							else if (value == "selected_back")
								id = static_cast<Char>(FontCodeType::SelectedBack);
							else if (value == "substitute")
								id = static_cast<Char>(FontCodeType::NotDefined);
							else
								id = utility::parseUInt(value);

							float advance(utility::parseValue<float>(element->findAttribute("advance")));
							FloatPoint bearing(utility::parseValue<FloatPoint>(element->findAttribute("bearing")));

							// texture coordinates
							FloatCoord coord(utility::parseValue<FloatCoord>(element->findAttribute("coord")));

							// glyph size, default to texture coordinate size
							std::string sizeString;
							FloatSize size(coord.width, coord.height);
							if (element->findAttribute("size", sizeString))
							{
								size = utility::parseValue<FloatSize>(sizeString);
							}

							if (advance == 0.0f)
								advance = size.width;

							GlyphInfo& glyphInfo = mCharMap.insert(CharMap::value_type(id, GlyphInfo(
								id,
								size.width,
								size.height,
								advance,
								bearing.left,
								bearing.top,
								FloatRect(
									coord.left / textureWidth,
									coord.top / textureHeight,
									coord.right() / textureWidth,
									coord.bottom() / textureHeight)
								))).first->second;

							if (id == FontCodeType::NotDefined)
								mSubstituteGlyphInfo = &glyphInfo;
						}
					}
				}
			}
		}
	}

	ITexture* ResourceManualFont::getTextureFont()
	{
		return mTexture;
	}

	int ResourceManualFont::getDefaultHeight()
	{
		return mDefaultHeight;
	}

} // namespace MyGUI
<|endoftext|>


<commit_before>/**
 * @file
 * @author Thaddeus Diamond <diamond@cs.yale.edu>
 * @version 0.1
 *
 * @section DESCRIPTION
 *
 * This is the implementation for a playback sensor (read from file I/O)
 */

#include <string>
#include "Playback/PlaybackSensor.h"

namespace Observation {

bool PlaybackSensor::SetValues(double const * const values, int num_values) {
  // This sensor cannot be set
  return false;
}

double const * const PlaybackSensor::GetValues() {
  // Return a one-element array to most recent value
  stale_ = !Poll();
  return values_;
}

bool PlaybackSensor::Poll() {
  // If file not opened, open it and fail if it's invalid
  if (!file_handle_) {
    running_ = true;

    timespec time_holder;
    clock_gettime(CLOCK_REALTIME, &time_holder);
    base_time_ = time_holder.tv_sec;

    file_handle_ = fopen(filename_, "r");
    if (!file_handle_) {
      Log(stderr, ERROR,
        string("Could not load file for playback").c_str());
      return false;
    }
  }

  // DO YOU KNOW WHAT TIME IT ISSSS???
  timespec time_holder;
  clock_gettime(CLOCK_REALTIME, &time_holder);
  double current_time_ms = ((time_holder.tv_sec - base_time_) * 1000) +
                           (static_cast<double>(time_holder.tv_nsec) / 1000000);

  // We want to do the I/O all at once, so we dynamically determine how many
  // frames we've "received" since the last poll. 0 indicates none, some o/w
  int num_frames_recvd;

  // If we're just starting...
  if (!last_poll_frame_)
    num_frames_recvd = 1;

  // Otherwise, we're polling at some arbitrary point
  else
    num_frames_recvd = floor((current_time_ms - last_poll_time_) * 3 / 100);

  // Shove the frames in a buffer so that we can back up one if need be (EOF)
  int num_frames_read = 0;
  char line_buffer[4096];
  for (int i = 0; i < num_frames_recvd; i++) {
    if (!fgets(line_buffer, sizeof(line_buffer), file_handle_)) {
      running_ = false;
      break;
    }
    num_frames_read++;
  }

  // Nothing's come from the sensor (polled too fast), don't update
  if (!num_frames_read)
    return false;

  char* scanner = &line_buffer[0],
      * leftover;
  for (int i = 0; i < num_values_; i++) {
    if (!scanner)
      return false;                             // Invalid line
    values_[i] = strtod(scanner, &leftover);
    scanner = leftover + 1;
  }

  // Only update the frame # and time if we successfully got data
  last_poll_frame_ += MIN(num_frames_read, num_frames_recvd);
  last_poll_time_   = num_frames_read == 0 ? last_poll_time_ : current_time_ms;
  return (num_frames_read > 0);
}

}  // namespace Observation
<commit_msg>Added more informative file load error message<commit_after>/**
 * @file
 * @author Thaddeus Diamond <diamond@cs.yale.edu>
 * @version 0.1
 *
 * @section DESCRIPTION
 *
 * This is the implementation for a playback sensor (read from file I/O)
 */

#include <string>
#include "Playback/PlaybackSensor.h"

namespace Observation {

bool PlaybackSensor::SetValues(double const * const values, int num_values) {
  // This sensor cannot be set
  return false;
}

double const * const PlaybackSensor::GetValues() {
  // Return a one-element array to most recent value
  stale_ = !Poll();
  return values_;
}

bool PlaybackSensor::Poll() {
  // If file not opened, open it and fail if it's invalid
  if (!file_handle_) {
    running_ = true;

    timespec time_holder;
    clock_gettime(CLOCK_REALTIME, &time_holder);
    base_time_ = time_holder.tv_sec;

    file_handle_ = fopen(filename_, "r");
    if (!file_handle_) {
      char buf[1024];
      snprintf(buf, sizeof(buf), "Could not load file %s for playback",
              filename_);
      Log(stderr, ERROR, buf);
      return false;
    }
  }

  timespec time_holder;
  clock_gettime(CLOCK_REALTIME, &time_holder);
  double current_time_ms = ((time_holder.tv_sec - base_time_) * 1000) +
                           (static_cast<double>(time_holder.tv_nsec) / 1000000);

  // We want to do the I/O all at once, so we dynamically determine how many
  // frames we've "received" since the last poll. 0 indicates none, some o/w
  int num_frames_recvd;

  // If we're just starting...
  if (!last_poll_frame_)
    num_frames_recvd = 1;

  // Otherwise, we're polling at some arbitrary point
  else
    num_frames_recvd = floor((current_time_ms - last_poll_time_) * 3 / 100);

  // Shove the frames in a buffer so that we can back up one if need be (EOF)
  int num_frames_read = 0;
  char line_buffer[4096];
  for (int i = 0; i < num_frames_recvd; i++) {
    if (!fgets(line_buffer, sizeof(line_buffer), file_handle_)) {
      running_ = false;
      break;
    }
    num_frames_read++;
  }

  // Nothing's come from the sensor (polled too fast), don't update
  if (!num_frames_read)
    return false;

  char* scanner = &line_buffer[0],
      * leftover;
  for (int i = 0; i < num_values_; i++) {
    if (!scanner)
      return false;                             // Invalid line
    values_[i] = strtod(scanner, &leftover);
    scanner = leftover + 1;
  }

  // Only update the frame # and time if we successfully got data
  last_poll_frame_ += MIN(num_frames_read, num_frames_recvd);
  last_poll_time_   = num_frames_read == 0 ? last_poll_time_ : current_time_ms;
  return (num_frames_read > 0);
}

}  // namespace Observation
<|endoftext|>


<commit_before>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2014 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh is free software: you can redistribute it and/or modify         *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh is distributed in the hope that it will be useful,              *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                              *
 *   $Date$                                                                  *
 *                                                                           *
\*===========================================================================*/

#ifndef PROPERTYMANAGER_HH_
#define PROPERTYMANAGER_HH_

#include <sstream>
#include <stdexcept>
#include <string>

namespace OpenMesh {

/**
 * This class is intended to manage the lifecycle of properties.
 * It also defines convenience operators to access the encapsulated
 * property's value.
 *
 * Usage example:
 *
 * \code
 * TriMesh mesh;
 * PropertyManager<VPropHandleT<bool>, TriMesh> visited(mesh, "visited.plugin-example.i8.informatik.rwth-aachen.de");
 *
 * for (TriMesh::VertexIter vh_it = mesh.begin(); ... ; ...) {
 *     if (!visited[*vh_it]) {
 *         visitComponent(mesh, *vh_it, visited);
 *     }
 * }
 * \endcode
 *
 */
template<typename PROPTYPE, typename MeshT>
class PropertyManager {
#if __cplusplus > 199711L or __GXX_EXPERIMENTAL_CXX0X__
    public:
        PropertyManager(const PropertyManager&) = delete;
        PropertyManager& operator=(const PropertyManager&) = delete;
#else
    private:
        /**
         * Noncopyable because there aren't no straightforward copy semantics.
         */
        PropertyManager(const PropertyManager&);

        /**
         * Noncopyable because there aren't no straightforward copy semantics.
         */
        PropertyManager& operator=(const PropertyManager&);
#endif

    public:
        /**
         * Constructor.
         *
         * Throws an \p std::runtime_error if \p existing is true and
         * no property named \p propname of the appropriate property type
         * exists.
         *
         * @param mesh The mesh on which to create the property.
         * @param propname The name of the property.
         * @param existing If false, a new property is created and its lifecycle is managed (i.e.
         * the property is deleted upon destruction of the PropertyManager instance). If true,
         * the instance merely acts as a convenience wrapper around an existing property with no
         * lifecycle management whatsoever.
         */
        PropertyManager(MeshT &mesh, const char *propname, bool existing = false) : mesh_(&mesh), retain_(existing), name_(propname) {
            if (existing) {
                if (!mesh_->get_property_handle(prop_, propname)) {
                    std::ostringstream oss;
                    oss << "Requested property handle \"" << propname << "\" does not exist.";
                    throw std::runtime_error(oss.str());
                }
            } else {
                mesh_->add_property(prop_, propname);
            }
        }

        PropertyManager() : mesh_(0), retain_(false) {
        }

        ~PropertyManager() {
            deleteProperty();
        }

        void swap(PropertyManager &rhs) {
            std::swap(mesh_, rhs.mesh_);
            std::swap(prop_, rhs.prop_);
            std::swap(retain_, rhs.retain_);
            std::swap(name_, rhs.name_);
        }

        static bool propertyExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy;
            return mesh.get_property_handle(dummy, propname);
        }

        bool isValid() const { return mesh_ != 0; }
        operator bool() const { return isValid(); }

        const PROPTYPE &getRawProperty() const { return prop_; }

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

        MeshT &getMesh() const { return *mesh_; }

#if __cplusplus > 199711L or __GXX_EXPERIMENTAL_CXX0X__
        /**
         * Move constructor. Transfers ownership (delete responsibility).
         */
        PropertyManager(PropertyManager &&rhs) : mesh_(rhs.mesh_), prop_(rhs.prop_), retain_(rhs.retain_), name_(rhs.name_) {
            rhs.retain_ = true;
        }

        /**
         * Move assignment. Transfers ownership (delete responsibility).
         */
        PropertyManager &operator=(PropertyManager &&rhs) {

            deleteProperty();

            mesh_ = rhs.mesh_;
            prop_ = rhs.prop_;
            retain_ = rhs.retain_;
            name_ = rhs.name_;
            rhs.retain_ = true;

            return *this;
        }

        /**
         * Create a property manager for the supplied property and mesh.
         * If the property doesn't exist, it is created. In any case,
         * lifecycle management is disabled.
         */
        static PropertyManager createIfNotExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy_prop;
            PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
            pm.retain();
            return std::move(pm);
        }

        PropertyManager duplicate(const char *clone_name) {
            PropertyManager pm(*mesh_, clone_name, false);
            pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
            return std::move(pm);
        }

        /**
         * Included for backwards compatibility with non-C++11 version.
         */
        PropertyManager move() {
            return std::move(*this);
        }

#else
        class Proxy {
            private:
                Proxy(MeshT *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) :
                    mesh_(mesh_), prop_(prop_), retain_(retain_), name_(name_) {}
                MeshT *mesh_;
                PROPTYPE prop_;
                bool retain_;
                std::string name_;

                friend class PropertyManager;
        };

        operator Proxy() {
            Proxy p(mesh_, prop_, retain_, name_);
            mesh_ = 0;
            retain_ = true;
            return p;
        }

        Proxy move() {
            return (Proxy)*this;
        }

        PropertyManager(Proxy p) : mesh_(p.mesh_), prop_(p.prop_), retain_(p.retain_), name_(p.name_) {}

        PropertyManager &operator=(Proxy p) {
            PropertyManager(p).swap(*this);
            return *this;
        }

        /**
         * Create a property manager for the supplied property and mesh.
         * If the property doesn't exist, it is created. In any case,
         * lifecycle management is disabled.
         */
        static Proxy createIfNotExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy_prop;
            PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
            pm.retain();
            return (Proxy)pm;
        }

        Proxy duplicate(const char *clone_name) {
            PropertyManager pm(*mesh_, clone_name, false);
            pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
            return (Proxy)pm;
        }
#endif

        /**
         * \brief Disable lifecycle management for this property.
         *
         * If this method is called, the encapsulated property will not be deleted
         * upon destruction of the PropertyManager instance.
         */
        inline void retain(bool doRetain = true) {
            retain_ = doRetain;
        }

        /**
         * Access the encapsulated property.
         */
        inline PROPTYPE &operator* () {
            return prop_;
        }

        /**
         * Access the encapsulated property.
         */
        inline const PROPTYPE &operator* () const {
            return prop_;
        }

        /**
         * Enables convenient access to the encapsulated property.
         *
         * For a usage example see this class' documentation.
         *
         * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.)
         */
        template<typename HandleType>
        inline typename PROPTYPE::reference operator[] (const HandleType &handle) {
            return mesh_->property(prop_, handle);
        }

        /**
         * Enables convenient access to the encapsulated property.
         *
         * For a usage example see this class' documentation.
         *
         * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.)
         */
        template<typename HandleType>
        inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const {
            return mesh_->property(prop_, handle);
        }

        /**
         * Conveniently set the property for an entire range of values.
         *
         * Examples:
         * \code
         * MeshT mesh;
         * PropertyManager<VPropHandleT<double>, MeshT> distance(
         *     mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de");
         * distance.set_range(
         *     mesh.vertices_begin(), mesh.vertices_end(),
         *     std::numeric_limits<double>::infinity());
         * \endcode
         * or
         * \code
         * MeshT::VertexHandle vh;
         * distance.set_range(
         *     mesh.vv_begin(vh), mesh.vv_end(vh),
         *     std::numeric_limits<double>::infinity());
         * \endcode
         *
         * @param begin Start iterator. Needs to dereference to HandleType.
         * @param end End iterator. (Exclusive.)
         * @param value The value the range will be set to.
         */
        template<typename HandleTypeIterator>
        void set_range(HandleTypeIterator begin, HandleTypeIterator end,
                typename PROPTYPE::const_reference value) {
            for (; begin != end; ++begin)
                (*this)[*begin] = value;
        }

        /**
         * Conveniently transfer the values managed by one property manager
         * onto the values managed by a different property manager.
         *
         * @param begin Start iterator. Needs to dereference to HandleType. Will
         * be used with this property manager.
         * @param end End iterator. (Exclusive.) Will be used with this property
         * manager.
         * @param dst_propmanager The destination property manager.
         * @param dst_begin Start iterator. Needs to dereference to the
         * HandleType of dst_propmanager. Will be used with dst_propmanager.
         * @param dst_end End iterator. (Exclusive.)
         * Will be used with dst_propmanager. Used to double check the bounds.
         */
        template<typename HandleTypeIterator, typename PROPTYPE_2,
                 typename MeshT_2, typename HandleTypeIterator_2>
        void copy_to(HandleTypeIterator begin, HandleTypeIterator end,
                PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager,
                HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const {

            for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) {
                dst_propmanager[dst_begin] = (*this)[*begin];
            }
        }

        template<typename RangeType, typename PROPTYPE_2,
                 typename MeshT_2, typename RangeType_2>
        void copy_to(RangeType range,
                PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager,
                RangeType_2 dst_range) const {
            copy_to(range.begin(), range.end(), dst_propmanager,
                    dst_range.begin(), dst_range.end());
        }

    private:
        void deleteProperty() {
            if (!retain_)
                mesh_->remove_property(prop_);
        }

    private:
        MeshT *mesh_;
        PROPTYPE prop_;
        bool retain_;
        std::string name_;
};

} /* namespace OpenMesh */
#endif /* PROPERTYMANAGER_HH_ */
<commit_msg>PropertyManager: Added static copy(...) convenience method.<commit_after>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2014 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh is free software: you can redistribute it and/or modify         *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh is distributed in the hope that it will be useful,              *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                              *
 *   $Date$                                                                  *
 *                                                                           *
\*===========================================================================*/

#ifndef PROPERTYMANAGER_HH_
#define PROPERTYMANAGER_HH_

#include <sstream>
#include <stdexcept>
#include <string>

namespace OpenMesh {

/**
 * This class is intended to manage the lifecycle of properties.
 * It also defines convenience operators to access the encapsulated
 * property's value.
 *
 * Usage example:
 *
 * \code
 * TriMesh mesh;
 * PropertyManager<VPropHandleT<bool>, TriMesh> visited(mesh, "visited.plugin-example.i8.informatik.rwth-aachen.de");
 *
 * for (TriMesh::VertexIter vh_it = mesh.begin(); ... ; ...) {
 *     if (!visited[*vh_it]) {
 *         visitComponent(mesh, *vh_it, visited);
 *     }
 * }
 * \endcode
 *
 */
template<typename PROPTYPE, typename MeshT>
class PropertyManager {
#if __cplusplus > 199711L or __GXX_EXPERIMENTAL_CXX0X__
    public:
        PropertyManager(const PropertyManager&) = delete;
        PropertyManager& operator=(const PropertyManager&) = delete;
#else
    private:
        /**
         * Noncopyable because there aren't no straightforward copy semantics.
         */
        PropertyManager(const PropertyManager&);

        /**
         * Noncopyable because there aren't no straightforward copy semantics.
         */
        PropertyManager& operator=(const PropertyManager&);
#endif

    public:
        /**
         * Constructor.
         *
         * Throws an \p std::runtime_error if \p existing is true and
         * no property named \p propname of the appropriate property type
         * exists.
         *
         * @param mesh The mesh on which to create the property.
         * @param propname The name of the property.
         * @param existing If false, a new property is created and its lifecycle is managed (i.e.
         * the property is deleted upon destruction of the PropertyManager instance). If true,
         * the instance merely acts as a convenience wrapper around an existing property with no
         * lifecycle management whatsoever.
         */
        PropertyManager(MeshT &mesh, const char *propname, bool existing = false) : mesh_(&mesh), retain_(existing), name_(propname) {
            if (existing) {
                if (!mesh_->get_property_handle(prop_, propname)) {
                    std::ostringstream oss;
                    oss << "Requested property handle \"" << propname << "\" does not exist.";
                    throw std::runtime_error(oss.str());
                }
            } else {
                mesh_->add_property(prop_, propname);
            }
        }

        PropertyManager() : mesh_(0), retain_(false) {
        }

        ~PropertyManager() {
            deleteProperty();
        }

        void swap(PropertyManager &rhs) {
            std::swap(mesh_, rhs.mesh_);
            std::swap(prop_, rhs.prop_);
            std::swap(retain_, rhs.retain_);
            std::swap(name_, rhs.name_);
        }

        static bool propertyExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy;
            return mesh.get_property_handle(dummy, propname);
        }

        bool isValid() const { return mesh_ != 0; }
        operator bool() const { return isValid(); }

        const PROPTYPE &getRawProperty() const { return prop_; }

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

        MeshT &getMesh() const { return *mesh_; }

#if __cplusplus > 199711L or __GXX_EXPERIMENTAL_CXX0X__
        /**
         * Move constructor. Transfers ownership (delete responsibility).
         */
        PropertyManager(PropertyManager &&rhs) : mesh_(rhs.mesh_), prop_(rhs.prop_), retain_(rhs.retain_), name_(rhs.name_) {
            rhs.retain_ = true;
        }

        /**
         * Move assignment. Transfers ownership (delete responsibility).
         */
        PropertyManager &operator=(PropertyManager &&rhs) {

            deleteProperty();

            mesh_ = rhs.mesh_;
            prop_ = rhs.prop_;
            retain_ = rhs.retain_;
            name_ = rhs.name_;
            rhs.retain_ = true;

            return *this;
        }

        /**
         * Create a property manager for the supplied property and mesh.
         * If the property doesn't exist, it is created. In any case,
         * lifecycle management is disabled.
         */
        static PropertyManager createIfNotExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy_prop;
            PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
            pm.retain();
            return std::move(pm);
        }

        PropertyManager duplicate(const char *clone_name) {
            PropertyManager pm(*mesh_, clone_name, false);
            pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
            return std::move(pm);
        }

        /**
         * Included for backwards compatibility with non-C++11 version.
         */
        PropertyManager move() {
            return std::move(*this);
        }

#else
        class Proxy {
            private:
                Proxy(MeshT *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) :
                    mesh_(mesh_), prop_(prop_), retain_(retain_), name_(name_) {}
                MeshT *mesh_;
                PROPTYPE prop_;
                bool retain_;
                std::string name_;

                friend class PropertyManager;
        };

        operator Proxy() {
            Proxy p(mesh_, prop_, retain_, name_);
            mesh_ = 0;
            retain_ = true;
            return p;
        }

        Proxy move() {
            return (Proxy)*this;
        }

        PropertyManager(Proxy p) : mesh_(p.mesh_), prop_(p.prop_), retain_(p.retain_), name_(p.name_) {}

        PropertyManager &operator=(Proxy p) {
            PropertyManager(p).swap(*this);
            return *this;
        }

        /**
         * Create a property manager for the supplied property and mesh.
         * If the property doesn't exist, it is created. In any case,
         * lifecycle management is disabled.
         */
        static Proxy createIfNotExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy_prop;
            PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
            pm.retain();
            return (Proxy)pm;
        }

        Proxy duplicate(const char *clone_name) {
            PropertyManager pm(*mesh_, clone_name, false);
            pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
            return (Proxy)pm;
        }
#endif

        /**
         * \brief Disable lifecycle management for this property.
         *
         * If this method is called, the encapsulated property will not be deleted
         * upon destruction of the PropertyManager instance.
         */
        inline void retain(bool doRetain = true) {
            retain_ = doRetain;
        }

        /**
         * Access the encapsulated property.
         */
        inline PROPTYPE &operator* () {
            return prop_;
        }

        /**
         * Access the encapsulated property.
         */
        inline const PROPTYPE &operator* () const {
            return prop_;
        }

        /**
         * Enables convenient access to the encapsulated property.
         *
         * For a usage example see this class' documentation.
         *
         * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.)
         */
        template<typename HandleType>
        inline typename PROPTYPE::reference operator[] (const HandleType &handle) {
            return mesh_->property(prop_, handle);
        }

        /**
         * Enables convenient access to the encapsulated property.
         *
         * For a usage example see this class' documentation.
         *
         * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.)
         */
        template<typename HandleType>
        inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const {
            return mesh_->property(prop_, handle);
        }

        /**
         * Conveniently set the property for an entire range of values.
         *
         * Examples:
         * \code
         * MeshT mesh;
         * PropertyManager<VPropHandleT<double>, MeshT> distance(
         *     mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de");
         * distance.set_range(
         *     mesh.vertices_begin(), mesh.vertices_end(),
         *     std::numeric_limits<double>::infinity());
         * \endcode
         * or
         * \code
         * MeshT::VertexHandle vh;
         * distance.set_range(
         *     mesh.vv_begin(vh), mesh.vv_end(vh),
         *     std::numeric_limits<double>::infinity());
         * \endcode
         *
         * @param begin Start iterator. Needs to dereference to HandleType.
         * @param end End iterator. (Exclusive.)
         * @param value The value the range will be set to.
         */
        template<typename HandleTypeIterator>
        void set_range(HandleTypeIterator begin, HandleTypeIterator end,
                typename PROPTYPE::const_reference value) {
            for (; begin != end; ++begin)
                (*this)[*begin] = value;
        }

        /**
         * Conveniently transfer the values managed by one property manager
         * onto the values managed by a different property manager.
         *
         * @param begin Start iterator. Needs to dereference to HandleType. Will
         * be used with this property manager.
         * @param end End iterator. (Exclusive.) Will be used with this property
         * manager.
         * @param dst_propmanager The destination property manager.
         * @param dst_begin Start iterator. Needs to dereference to the
         * HandleType of dst_propmanager. Will be used with dst_propmanager.
         * @param dst_end End iterator. (Exclusive.)
         * Will be used with dst_propmanager. Used to double check the bounds.
         */
        template<typename HandleTypeIterator, typename PROPTYPE_2,
                 typename MeshT_2, typename HandleTypeIterator_2>
        void copy_to(HandleTypeIterator begin, HandleTypeIterator end,
                PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager,
                HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const {

            for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) {
                dst_propmanager[*dst_begin] = (*this)[*begin];
            }
        }

        template<typename RangeType, typename PROPTYPE_2,
                 typename MeshT_2, typename RangeType_2>
        void copy_to(const RangeType &range,
                PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager,
                const RangeType_2 &dst_range) const {
            copy_to(range.begin(), range.end(), dst_propmanager,
                    dst_range.begin(), dst_range.end());
        }

        /**
         * Copy the values of a property from a source range to
         * a target range. The source range must not be smaller than the
         * target range.
         *
         * @param prop_name Name of the property to copy. Must exist on the
         * source mesh. Will be created on the target mesh if it doesn't exist.
         *
         * @param src_mesh Source mesh from which to copy.
         * @param src_range Source range which to copy. Must not be smaller than
         * dst_range.
         * @param dst_mesh Destination mesh on which to copy.
         * @param dst_range Destination range.
         */
        template<typename RangeType, typename MeshT_2, typename RangeType_2>
        static void copy(const char *prop_name,
                MeshT &src_mesh, const RangeType &src_range,
                MeshT_2 &dst_mesh, const RangeType_2 &dst_range) {

            typedef OpenMesh::PropertyManager<PROPTYPE, MeshT> DstPM;
            DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name));

            typedef OpenMesh::PropertyManager<PROPTYPE, MeshT_2> SrcPM;
            SrcPM src(src_mesh, prop_name, true);

            src.copy_to(src_range, dst, dst_range);
        }

    private:
        void deleteProperty() {
            if (!retain_)
                mesh_->remove_property(prop_);
        }

    private:
        MeshT *mesh_;
        PROPTYPE prop_;
        bool retain_;
        std::string name_;
};

} /* namespace OpenMesh */
#endif /* PROPERTYMANAGER_HH_ */
<|endoftext|>


<commit_before>#include "details/compiler/compiler.h"
#include "details/compiler/compdb.h"
#include "details/program/program.h"
#include "details/reporting/report.h"
#include "details/errors/errors.h"
#include "details/pass/a-src2ast/ast-from-source.h"
#include "details/pass/b-ast-normalize/normalize.h"
#include "details/pass/c-ast2ir/source-ast-to-ir.h"
#include "details/pass/d-object-map/attach.h"
#include "details/semantic/atom-factory.h"
#include "details/intrinsic/std.core.h"
#include "details/compiler/report.h"
#include "libnanyc-config.h"
#include "libnanyc-traces.h"
#include "embed-nsl.hxx" // generated
#include <yuni/io/file.h>
#include <libnanyc.h>
#include <utility>
#include <memory>

namespace ny {
namespace compiler {

namespace {

constexpr uint32_t memoryHardlimit = 64 * 1024 * 1024;

Logs::Report buildGenerateReport(void* ptr, Logs::Level level) {
	return (*((ny::Logs::Report*) ptr)).fromErrLevel(level);
}

void copySourceOpts(ny::compiler::Source& source, const nysource_opts_t& opts) {
	if (opts.filename.len != 0) {
		if (unlikely(opts.filename.len > memoryHardlimit))
			throw "input filename bigger than internal limit";
		yuni::IO::Canonicalize(source.storageFilename, AnyString{opts.filename.c_str, static_cast<uint32_t>(opts.filename.len)});
		source.filename = source.storageFilename;
	}
	if (opts.content.len != 0) {
		if (unlikely(opts.content.len > memoryHardlimit))
			throw "input source content bigger than internal limit";
		source.storageContent.assign(opts.content.c_str, static_cast<uint32_t>(opts.content.len));
		source.content = source.storageContent;
	}
}

bool compileSource(ny::Logs::Report& mainreport, ny::compiler::Compdb& compdb, ny::compiler::Source& source, const nycompile_opts_t& gopts) {
	auto report = mainreport.subgroup();
	report.data().origins.location.filename = source.filename;
	report.data().origins.location.target.clear();
	bool compiled = true;
	compiled &= makeASTFromSource(source);
	compiled &= passDuplicateAndNormalizeAST(source, report);
	compiled &= passTransformASTToIR(source, report, gopts);
	compiled  = compiled and attach(compdb, source);
	return compiled;
}

bool importSourceAndCompile(ny::Logs::Report& mainreport, ny::compiler::Compdb& compdb, ny::compiler::Source& source, const nycompile_opts_t& gopts, const nysource_opts_t& opts) {
	copySourceOpts(source, opts);
	return compileSource(mainreport, compdb, source, gopts);
}

Atom& findEntrypointAtom(Atom& root, const AnyString& entrypoint) {
	Atom* atom = nullptr;
	root.eachChild(entrypoint, [&](Atom & child) -> bool {
		if (unlikely(atom != nullptr))
			throw "': multiple entry points found";
		atom = &child;
		return true;
	});
	if (unlikely(!atom))
		throw "()': function not found";
	if (unlikely(not atom->isFunction() or atom->isClassMember()))
		throw "': the atom is not a function";
	return *atom;
}

bool instanciate(ny::compiler::Compdb& compdb, ny::Logs::Report& report, AnyString entrypoint) {
	using ParameterList = decltype(ny::semantic::FuncOverloadMatch::result.params);
	try {
		auto& atom = findEntrypointAtom(compdb.cdeftable.atoms.root, entrypoint);
		atom.funcinfo.raisedErrors.noleaks.enabled = true;
		ParameterList params;
		ParameterList tmplparams;
		ClassdefTableView cdeftblView{compdb.cdeftable};
		ny::semantic::Settings settings(atom, cdeftblView, compdb, params, tmplparams);
		bool instanciated = ny::semantic::instanciateAtom(settings);
		report.appendEntry(settings.report);
		if (config::traces::atomTable)
			compdb.cdeftable.atoms.root.printTree(compdb.cdeftable);
		if (likely(instanciated)) {
			compdb.entrypoint.atomid = atom.atomid;
			compdb.entrypoint.instanceid = settings.instanceid;
			return not report.hasErrors();
		}
	}
	catch (const char* e) {
		report.error() << "failed to instanciate '" << entrypoint << e;
	}
	compdb.entrypoint.atomid = (uint32_t) -1;
	compdb.entrypoint.instanceid = (uint32_t) -1;
	return false;
}

std::unique_ptr<ny::Program> compile(ny::compiler::Compdb& compdb) {
	ny::Logs::Report report{compdb.messages};
	Logs::Handler errorHandler{&report, &buildGenerateReport};
	try {
		auto& opts = compdb.opts;
		uint32_t scount = opts.sources.count;
		if (unlikely(scount == 0))
			throw "no input source code";
		if (config::importNSL)
			ny::intrinsic::import::all(compdb.intrinsics);
		if (config::importNSL)
			scount += corefilesCount;
		if (unlikely(opts.with_nsl_unittests == nytrue))
			scount += unittestCount;
		auto& sources = compdb.sources;
		sources.count = scount;
		sources.items = std::make_unique<Source[]>(scount);
		bool compiled = true;
		uint32_t offset = 0;
		if (config::importNSL) {
			registerNSLCoreFiles(sources, offset, [&](ny::compiler::Source& source) {
				compiled &= compileSource(report, compdb, source, opts);
			});
		}
		if (opts.with_nsl_unittests == nytrue) {
			registerUnittestFiles(sources, offset, [&](ny::compiler::Source& source) {
				compiled &= compileSource(report, compdb, source, opts);
			});
		}
		for (uint32_t i = 0; i != opts.sources.count; ++i) {
			auto& source = sources[offset + i];
			compiled &= importSourceAndCompile(report, compdb, source, opts, opts.sources.items[i]);
		}
		compiled = compiled
			and compdb.cdeftable.atoms.fetchAndIndexCoreObjects() // indexing bool, u32, f64...
			and ny::semantic::resolveStrictParameterTypes(compdb, compdb.cdeftable.atoms.root); // typedef
		if (config::traces::preAtomTable)
			compdb.cdeftable.atoms.root.printTree(ClassdefTableView{compdb.cdeftable});
		if (unlikely(not compiled))
			return nullptr;
		auto& entrypoint = compdb.opts.entrypoint;
		if (unlikely(entrypoint.len == 0))
			return nullptr;
		bool epinst = instanciate(compdb, report, AnyString(entrypoint.c_str, static_cast<uint32_t>(entrypoint.len)));
		if (config::traces::raisedErrorSummary)
			ny::compiler::report::raisedErrorsForAllAtoms(compdb, report);
		if (unlikely(not epinst))
			return nullptr;
		return std::make_unique<ny::Program>();
	}
	catch (const std::bad_alloc&) {
		report.ice() << "not enough memory when compiling";
	}
	catch (const std::exception& e) {
		report.ice() << "exception: " << e.what();
	}
	catch (const char* e) {
		report.error() << e;
	}
	catch (...) {
		report.ice() << "uncaught exception when compiling";
	}
	return nullptr;
}

void pleaseReport(nycompile_opts_t& opts, std::unique_ptr<ny::compiler::Compdb>& compdb) {
	auto* rp = reinterpret_cast<const nyreport_t*>(&compdb->messages);
	if (opts.on_report)
		opts.on_report(opts.userdata, rp);
	else
		nyreport_print_stdout(rp);
}

} // namespace

nyprogram_t* compile(nycompile_opts_t& opts) {
	try {
		if (opts.on_build_start)
			opts.userdata = opts.on_build_start(opts.userdata);
		auto compdb = std::make_unique<Compdb>(opts);
		auto program = compile(*compdb);
		if (opts.on_build_stop)
			opts.on_build_stop(opts.userdata, (program ? nytrue : nyfalse));
		if (not compdb->messages.entries.empty())
			pleaseReport(opts, compdb);
		if (unlikely(!program))
			return nullptr;
		program->compdb = std::move(compdb);
		return ny::Program::pointer(program.release());
	}
	catch (...) {
	}
	if (opts.on_build_stop)
		opts.on_build_stop(opts.userdata, nyfalse);
	return nullptr;
}

} // namespace compiler
} // namespace ny
<commit_msg>compiler: abort compilation when just retrieving the list of unittests<commit_after>#include "details/compiler/compiler.h"
#include "details/compiler/compdb.h"
#include "details/program/program.h"
#include "details/reporting/report.h"
#include "details/errors/errors.h"
#include "details/pass/a-src2ast/ast-from-source.h"
#include "details/pass/b-ast-normalize/normalize.h"
#include "details/pass/c-ast2ir/source-ast-to-ir.h"
#include "details/pass/d-object-map/attach.h"
#include "details/semantic/atom-factory.h"
#include "details/intrinsic/std.core.h"
#include "details/compiler/report.h"
#include "libnanyc-config.h"
#include "libnanyc-traces.h"
#include "embed-nsl.hxx" // generated
#include <yuni/io/file.h>
#include <libnanyc.h>
#include <utility>
#include <memory>

namespace ny {
namespace compiler {

namespace {

constexpr uint32_t memoryHardlimit = 64 * 1024 * 1024;

Logs::Report buildGenerateReport(void* ptr, Logs::Level level) {
	return (*((ny::Logs::Report*) ptr)).fromErrLevel(level);
}

void copySourceOpts(ny::compiler::Source& source, const nysource_opts_t& opts) {
	if (opts.filename.len != 0) {
		if (unlikely(opts.filename.len > memoryHardlimit))
			throw "input filename bigger than internal limit";
		yuni::IO::Canonicalize(source.storageFilename, AnyString{opts.filename.c_str, static_cast<uint32_t>(opts.filename.len)});
		source.filename = source.storageFilename;
	}
	if (opts.content.len != 0) {
		if (unlikely(opts.content.len > memoryHardlimit))
			throw "input source content bigger than internal limit";
		source.storageContent.assign(opts.content.c_str, static_cast<uint32_t>(opts.content.len));
		source.content = source.storageContent;
	}
}

bool compileSource(ny::Logs::Report& mainreport, ny::compiler::Compdb& compdb, ny::compiler::Source& source, const nycompile_opts_t& gopts) {
	auto report = mainreport.subgroup();
	report.data().origins.location.filename = source.filename;
	report.data().origins.location.target.clear();
	bool compiled = true;
	compiled &= makeASTFromSource(source);
	compiled &= passDuplicateAndNormalizeAST(source, report);
	compiled &= passTransformASTToIR(source, report, gopts);
	compiled  = compiled and attach(compdb, source);
	return compiled;
}

bool importSourceAndCompile(ny::Logs::Report& mainreport, ny::compiler::Compdb& compdb, ny::compiler::Source& source, const nycompile_opts_t& gopts, const nysource_opts_t& opts) {
	copySourceOpts(source, opts);
	return compileSource(mainreport, compdb, source, gopts);
}

Atom& findEntrypointAtom(Atom& root, const AnyString& entrypoint) {
	Atom* atom = nullptr;
	root.eachChild(entrypoint, [&](Atom & child) -> bool {
		if (unlikely(atom != nullptr))
			throw "': multiple entry points found";
		atom = &child;
		return true;
	});
	if (unlikely(!atom))
		throw "()': function not found";
	if (unlikely(not atom->isFunction() or atom->isClassMember()))
		throw "': the atom is not a function";
	return *atom;
}

bool instanciate(ny::compiler::Compdb& compdb, ny::Logs::Report& report, AnyString entrypoint) {
	using ParameterList = decltype(ny::semantic::FuncOverloadMatch::result.params);
	try {
		auto& atom = findEntrypointAtom(compdb.cdeftable.atoms.root, entrypoint);
		atom.funcinfo.raisedErrors.noleaks.enabled = true;
		ParameterList params;
		ParameterList tmplparams;
		ClassdefTableView cdeftblView{compdb.cdeftable};
		ny::semantic::Settings settings(atom, cdeftblView, compdb, params, tmplparams);
		bool instanciated = ny::semantic::instanciateAtom(settings);
		report.appendEntry(settings.report);
		if (config::traces::atomTable)
			compdb.cdeftable.atoms.root.printTree(compdb.cdeftable);
		if (likely(instanciated)) {
			compdb.entrypoint.atomid = atom.atomid;
			compdb.entrypoint.instanceid = settings.instanceid;
			return not report.hasErrors();
		}
	}
	catch (const char* e) {
		report.error() << "failed to instanciate '" << entrypoint << e;
	}
	compdb.entrypoint.atomid = (uint32_t) -1;
	compdb.entrypoint.instanceid = (uint32_t) -1;
	return false;
}

std::unique_ptr<ny::Program> compile(ny::compiler::Compdb& compdb) {
	ny::Logs::Report report{compdb.messages};
	Logs::Handler errorHandler{&report, &buildGenerateReport};
	try {
		auto& opts = compdb.opts;
		uint32_t scount = opts.sources.count;
		if (unlikely(scount == 0))
			throw "no input source code";
		if (config::importNSL)
			ny::intrinsic::import::all(compdb.intrinsics);
		if (config::importNSL)
			scount += corefilesCount;
		if (unlikely(opts.with_nsl_unittests == nytrue))
			scount += unittestCount;
		auto& sources = compdb.sources;
		sources.count = scount;
		sources.items = std::make_unique<Source[]>(scount);
		bool compiled = true;
		uint32_t offset = 0;
		if (config::importNSL) {
			registerNSLCoreFiles(sources, offset, [&](ny::compiler::Source& source) {
				compiled &= compileSource(report, compdb, source, opts);
			});
		}
		if (opts.with_nsl_unittests == nytrue) {
			registerUnittestFiles(sources, offset, [&](ny::compiler::Source& source) {
				compiled &= compileSource(report, compdb, source, opts);
			});
		}
		for (uint32_t i = 0; i != opts.sources.count; ++i) {
			auto& source = sources[offset + i];
			compiled &= importSourceAndCompile(report, compdb, source, opts, opts.sources.items[i]);
		}
		compiled = compiled
			and likely(compdb.opts.on_unittest == nullptr)
			and compdb.cdeftable.atoms.fetchAndIndexCoreObjects() // indexing bool, u32, f64...
			and ny::semantic::resolveStrictParameterTypes(compdb, compdb.cdeftable.atoms.root); // typedef
		if (config::traces::preAtomTable)
			compdb.cdeftable.atoms.root.printTree(ClassdefTableView{compdb.cdeftable});
		if (unlikely(not compiled))
			return nullptr;
		auto& entrypoint = compdb.opts.entrypoint;
		if (unlikely(entrypoint.len == 0))
			return nullptr;
		bool epinst = instanciate(compdb, report, AnyString(entrypoint.c_str, static_cast<uint32_t>(entrypoint.len)));
		if (config::traces::raisedErrorSummary)
			ny::compiler::report::raisedErrorsForAllAtoms(compdb, report);
		if (unlikely(not epinst))
			return nullptr;
		return std::make_unique<ny::Program>();
	}
	catch (const std::bad_alloc&) {
		report.ice() << "not enough memory when compiling";
	}
	catch (const std::exception& e) {
		report.ice() << "exception: " << e.what();
	}
	catch (const char* e) {
		report.error() << e;
	}
	catch (...) {
		report.ice() << "uncaught exception when compiling";
	}
	return nullptr;
}

void pleaseReport(nycompile_opts_t& opts, std::unique_ptr<ny::compiler::Compdb>& compdb) {
	auto* rp = reinterpret_cast<const nyreport_t*>(&compdb->messages);
	if (opts.on_report)
		opts.on_report(opts.userdata, rp);
	else
		nyreport_print_stdout(rp);
}

} // namespace

nyprogram_t* compile(nycompile_opts_t& opts) {
	try {
		if (opts.on_build_start)
			opts.userdata = opts.on_build_start(opts.userdata);
		auto compdb = std::make_unique<Compdb>(opts);
		auto program = compile(*compdb);
		if (opts.on_build_stop)
			opts.on_build_stop(opts.userdata, (program ? nytrue : nyfalse));
		if (not compdb->messages.entries.empty())
			pleaseReport(opts, compdb);
		if (unlikely(!program))
			return nullptr;
		program->compdb = std::move(compdb);
		return ny::Program::pointer(program.release());
	}
	catch (...) {
	}
	if (opts.on_build_stop)
		opts.on_build_stop(opts.userdata, nyfalse);
	return nullptr;
}

} // namespace compiler
} // namespace ny
<|endoftext|>


<commit_before>
#include <QTcpSocket>
#include <QDir>
#include <QTextStream>
#include <QDebug>
#include <QtCrypto>
#include <QUuid>

#include "netcatpaste.h"

netcatpaste::netcatpaste() :
        paste_dir("paste"),
        paste_site("http://p.smar.fi") {

    checkPasteDir();

    bool succeeded = server.listen(QHostAddress::Any, 1234);
    if(!succeeded) {
        qDebug()<<"Failed to bind the server to port 1234";
        return;
    }
    connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection()));
}

void netcatpaste::checkPasteDir() {
    QDir dir(".");
    dir.mkdir(paste_dir);
}

void netcatpaste::newConnection() {
    qDebug()<<"New connection...";
    QTcpSocket *socket = server.nextPendingConnection();
    QByteArray array;
    if(!socket->waitForReadyRead()) {
        return;
    }

    QByteArray data;

    forever {
        QByteArray received = socket->readAll();
        data.append(received);

        if(!socket->waitForReadyRead(3000)) {
            break;
        }
    }

    QString file_name = createPaste(data);

    QString url = paste_site + "/" + file_name;
    //QString message = "Your paste can be found at:\n" + url + "\n";
    QString message = url + "\n";
    socket->write(message.toUtf8().data());
    sleep(3);
    socket->close();
}

QString netcatpaste::createPaste(QByteArray byte_array) {
    QCA::Hash hash = QCA::Hash("sha1");
    QCA::SecureArray secure_array(byte_array);
    hash.update(secure_array);
    QCA::SecureArray result_array = hash.final();
    QString result_string = QCA::arrayToHex(result_array.toByteArray());
    hash.clear();
    QString file_name = paste_dir + "/" + result_string;
    QFile file(file_name);
    if(!file.open(QFile::WriteOnly)) {
        qDebug() << "Weren’t able to open file" << file_name;
    }
    QTextStream out(&file);
    out << byte_array;
    return result_string;
}

netcatpaste::~netcatpaste() {
    //nya
}

#include "netcatpaste.moc"
<commit_msg>flush after writing...<commit_after>
#include <QTcpSocket>
#include <QDir>
#include <QTextStream>
#include <QDebug>
#include <QtCrypto>
#include <QUuid>

#include "netcatpaste.h"

netcatpaste::netcatpaste() :
        paste_dir("paste"),
        paste_site("http://p.smar.fi") {

    checkPasteDir();

    bool succeeded = server.listen(QHostAddress::Any, 1234);
    if(!succeeded) {
        qDebug()<<"Failed to bind the server to port 1234";
        return;
    }
    connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection()));
}

void netcatpaste::checkPasteDir() {
    QDir dir(".");
    dir.mkdir(paste_dir);
}

void netcatpaste::newConnection() {
    qDebug()<<"New connection...";
    QTcpSocket *socket = server.nextPendingConnection();
    QByteArray array;
    if(!socket->waitForReadyRead()) {
        return;
    }

    QByteArray data;

    forever {
        QByteArray received = socket->readAll();
        data.append(received);

        if(!socket->waitForReadyRead(3000)) {
            break;
        }
    }

    QString file_name = createPaste(data);

    QString url = paste_site + "/" + file_name;
    //QString message = "Your paste can be found at:\n" + url + "\n";
    QString message = url + "\n";
    socket->write(message.toUtf8().data());
    socket->flush();
    sleep(3);
    socket->close();
}

QString netcatpaste::createPaste(QByteArray byte_array) {
    QCA::Hash hash = QCA::Hash("sha1");
    QCA::SecureArray secure_array(byte_array);
    hash.update(secure_array);
    QCA::SecureArray result_array = hash.final();
    QString result_string = QCA::arrayToHex(result_array.toByteArray());
    hash.clear();
    QString file_name = paste_dir + "/" + result_string;
    QFile file(file_name);
    if(!file.open(QFile::WriteOnly)) {
        qDebug() << "Weren’t able to open file" << file_name;
    }
    QTextStream out(&file);
    out << byte_array;
    return result_string;
}

netcatpaste::~netcatpaste() {
    //nya
}

#include "netcatpaste.moc"
<|endoftext|>


<commit_before>#include "Runtime/GuiSys/CGuiTextSupport.hpp"

#include "Runtime/CSimplePool.hpp"
#include "Runtime/Graphics/CGraphics.hpp"
#include "Runtime/Graphics/CGraphicsPalette.hpp"
#include "Runtime/GuiSys/CFontImageDef.hpp"
#include "Runtime/GuiSys/CGuiSys.hpp"
#include "Runtime/GuiSys/CRasterFont.hpp"
#include "Runtime/GuiSys/CTextExecuteBuffer.hpp"
#include "Runtime/GuiSys/CTextParser.hpp"

namespace urde {

CGuiTextSupport::CGuiTextSupport(CAssetId fontId, const CGuiTextProperties& props, const zeus::CColor& fontCol,
                                 const zeus::CColor& outlineCol, const zeus::CColor& geomCol, s32 padX, s32 padY,
                                 CSimplePool* store, CGuiWidget::EGuiModelDrawFlags drawFlags)
: x14_props(props)
, x24_fontColor(fontCol)
, x28_outlineColor(outlineCol)
, x2c_geometryColor(geomCol)
, x34_extentX(padX)
, x38_extentY(padY)
, x5c_fontId(fontId)
, m_drawFlags(drawFlags) {
  x2cc_font = store->GetObj({SBIG('FONT'), fontId});
}

CTextRenderBuffer* CGuiTextSupport::GetCurrentPageRenderBuffer() {
  if (x60_renderBuf && !x308_multipageFlag) {
    return &*x60_renderBuf;
  }

  if (!x308_multipageFlag || x2ec_renderBufferPages.size() <= x304_pageCounter) {
    return nullptr;
  }

  int idx = 0;
  for (CTextRenderBuffer& buf : x2ec_renderBufferPages) {
    if (idx++ == x304_pageCounter) {
      return &buf;
    }
  }

  return nullptr;
}

const CTextRenderBuffer* CGuiTextSupport::GetCurrentPageRenderBuffer() const {
  if (x60_renderBuf && !x308_multipageFlag) {
    return &*x60_renderBuf;
  }

  if (!x308_multipageFlag || x2ec_renderBufferPages.size() <= x304_pageCounter) {
    return nullptr;
  }

  int idx = 0;
  for (const CTextRenderBuffer& buf : x2ec_renderBufferPages) {
    if (idx++ == x304_pageCounter) {
      return &buf;
    }
  }

  return nullptr;
}

float CGuiTextSupport::GetCurrentAnimationOverAge() const {
  float ret = 0.f;
  if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    if (x50_typeEnable) {
      if (x40_primStartTimes.size()) {
        auto& lastTime = x40_primStartTimes.back();
        ret = std::max(ret, (buf->GetPrimitiveCount() - lastTime.second) / x58_chRate + lastTime.first);
      } else {
        ret = std::max(ret, buf->GetPrimitiveCount() / x58_chRate);
      }
    }
  }
  return ret;
}

float CGuiTextSupport::GetNumCharsTotal() const {
  if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    if (x50_typeEnable) {
      return buf->GetPrimitiveCount();
    }
  }
  return 0.f;
}

float CGuiTextSupport::GetNumCharsPrinted() const {
  if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    if (x50_typeEnable) {
      const float charsPrinted = x3c_curTime * x58_chRate;
      return std::min(charsPrinted, float(buf->GetPrimitiveCount()));
    }
  }
  return 0.f;
}

float CGuiTextSupport::GetTotalAnimationTime() const {
  if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    if (x50_typeEnable) {
      return buf->GetPrimitiveCount() / x58_chRate;
    }
  }
  return 0.f;
}

bool CGuiTextSupport::IsAnimationDone() const { return x3c_curTime >= GetTotalAnimationTime(); }

void CGuiTextSupport::SetTypeWriteEffectOptions(bool enable, float chFadeTime, float chRate) {
  x50_typeEnable = enable;
  x54_chFadeTime = std::max(chFadeTime, 0.0001f);
  x58_chRate = std::max(chRate, 1.f);
  if (enable) {
    if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
      float chStartTime = 0.f;
      for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) {
        for (const std::pair<float, int>& p : x40_primStartTimes) {
          if (p.second < i)
            continue;
          if (p.second != i)
            break;
          chStartTime = p.first;
          break;
        }

        buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f));
        chStartTime += 1.f / x58_chRate;
      }
    }
  }
}

void CGuiTextSupport::Update(float dt) {
  if (x50_typeEnable) {
    if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
      float chStartTime = 0.f;
      for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) {
        for (const std::pair<float, int>& p : x40_primStartTimes) {
          if (p.second < i)
            continue;
          if (p.second != i)
            break;
          chStartTime = p.first;
          break;
        }

        buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f));
        chStartTime += 1.f / x58_chRate;
      }
    }
    x3c_curTime += dt;
  }

  x10_curTimeMod900 = std::fmod(x10_curTimeMod900 + dt, 900.f);
}

void CGuiTextSupport::ClearRenderBuffer() {
  x60_renderBuf = std::nullopt;
  x2ec_renderBufferPages.clear();
}

void CGuiTextSupport::CheckAndRebuildTextBuffer() {
  g_TextExecuteBuf->Clear();
  g_TextExecuteBuf->x18_textState.x7c_enableWordWrap = x14_props.x0_wordWrap;
  g_TextExecuteBuf->BeginBlock(0, 0, x34_extentX, x38_extentY, x30_imageBaseline,
                               ETextDirection(!x14_props.x1_horizontal), x14_props.x4_justification,
                               x14_props.x8_vertJustification);
  g_TextExecuteBuf->AddColor(EColorType::Main, x24_fontColor);
  g_TextExecuteBuf->AddColor(EColorType::Outline, x28_outlineColor);

  std::u16string initStr;
  if (x5c_fontId.IsValid())
    initStr = fmt::format(FMT_STRING(u"&font={};"), x5c_fontId);
  initStr += x0_string;

  g_TextParser->ParseText(*g_TextExecuteBuf, initStr.c_str(), initStr.size(), x14_props.xc_txtrMap);

  g_TextExecuteBuf->EndBlock();
}

bool CGuiTextSupport::CheckAndRebuildRenderBuffer() {
  if (x308_multipageFlag || x60_renderBuf)
    if (!x308_multipageFlag || x2ec_renderBufferPages.size())
      return true;

  CheckAndRebuildTextBuffer();
  x2bc_assets = g_TextExecuteBuf->GetAssets();

  if (!_GetIsTextSupportFinishedLoading())
    return false;

  CheckAndRebuildTextBuffer();
  if (x308_multipageFlag) {
    zeus::CVector2i extent(x34_extentX, x38_extentY);
    x2ec_renderBufferPages = g_TextExecuteBuf->BuildRenderBufferPages(extent, m_drawFlags);
  } else {
    x60_renderBuf.emplace(g_TextExecuteBuf->BuildRenderBuffer(m_drawFlags));
    x2dc_oneBufBounds = x60_renderBuf->AccumulateTextBounds();
  }
  g_TextExecuteBuf->Clear();
  Update(0.f);

  return true;
}

const std::pair<zeus::CVector2i, zeus::CVector2i>& CGuiTextSupport::GetBounds() {
  CheckAndRebuildRenderBuffer();
  return x2dc_oneBufBounds;
}

void CGuiTextSupport::AutoSetExtent() {
  const auto& bounds = GetBounds();
  x34_extentX = bounds.second.x;
  x38_extentY = bounds.second.y;
}

void CGuiTextSupport::Render() {
  CheckAndRebuildRenderBuffer();
  if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    SCOPED_GRAPHICS_DEBUG_GROUP("CGuiTextSupport::Render", zeus::skBlue);
    zeus::CTransform oldModel = CGraphics::g_GXModelMatrix;
    CGraphics::SetModelMatrix(oldModel * zeus::CTransform::Scale(1.f, 1.f, -1.f));
    buf->Render(x2c_geometryColor, x10_curTimeMod900);
    CGraphics::SetModelMatrix(oldModel);
  }
}

void CGuiTextSupport::SetGeometryColor(const zeus::CColor& col) { x2c_geometryColor = col; }

void CGuiTextSupport::SetOutlineColor(const zeus::CColor& col) {
  if (col != x28_outlineColor) {
    ClearRenderBuffer();
    x28_outlineColor = col;
  }
}

void CGuiTextSupport::SetFontColor(const zeus::CColor& col) {
  if (col != x24_fontColor) {
    ClearRenderBuffer();
    x24_fontColor = col;
  }
}

void CGuiTextSupport::AddText(std::u16string_view str) {
  if (x60_renderBuf) {
    const float t = GetCurrentAnimationOverAge();
    x40_primStartTimes.emplace_back(std::max(t, x3c_curTime), x60_renderBuf->GetPrimitiveCount());
  }
  x0_string += str;
  ClearRenderBuffer();
}

void CGuiTextSupport::SetText(std::u16string_view str, bool multipage) {
  if (x0_string != str) {
    x40_primStartTimes.clear();
    x3c_curTime = 0.f;
    x0_string = str;
    ClearRenderBuffer();
    x308_multipageFlag = multipage;
    x304_pageCounter = 0;
  }
}

void CGuiTextSupport::SetText(std::string_view str, bool multipage) { SetText(hecl::UTF8ToChar16(str), multipage); }

bool CGuiTextSupport::_GetIsTextSupportFinishedLoading() {
  for (CToken& tok : x2bc_assets) {
    tok.Lock();

    if (!tok.IsLoaded()) {
      return false;
    }
  }

  if (!x2cc_font) {
    return true;
  }

  if (x2cc_font.IsLoaded()) {
    return x2cc_font->IsFinishedLoading();
  }

  return false;
}

void CGuiTextSupport::SetJustification(EJustification j) {
  if (j != x14_props.x4_justification) {
    x14_props.x4_justification = j;
    ClearRenderBuffer();
  }
}

void CGuiTextSupport::SetVerticalJustification(EVerticalJustification j) {
  if (j != x14_props.x8_vertJustification) {
    x14_props.x8_vertJustification = j;
    ClearRenderBuffer();
  }
}

void CGuiTextSupport::SetImageBaseline(bool b) {
  if (b != x30_imageBaseline) {
    x30_imageBaseline = b;
    ClearRenderBuffer();
  }
}

bool CGuiTextSupport::GetIsTextSupportFinishedLoading() {
  CheckAndRebuildRenderBuffer();
  return _GetIsTextSupportFinishedLoading();
}

void CGuiTextSupport::SetControlTXTRMap(const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  if (x14_props.xc_txtrMap != txtrMap) {
    x14_props.xc_txtrMap = txtrMap;
    ClearRenderBuffer();
  }
}

int CGuiTextSupport::GetTotalPageCount() {
  if (CheckAndRebuildRenderBuffer())
    return x2ec_renderBufferPages.size();
  return -1;
}

void CGuiTextSupport::SetPage(int page) {
  x304_pageCounter = page;
  x40_primStartTimes.clear();
  x3c_curTime = 0.f;
}

} // namespace urde
<commit_msg>CGuiTextSupport: Invert conditionals where applicable<commit_after>#include "Runtime/GuiSys/CGuiTextSupport.hpp"

#include "Runtime/CSimplePool.hpp"
#include "Runtime/Graphics/CGraphics.hpp"
#include "Runtime/Graphics/CGraphicsPalette.hpp"
#include "Runtime/GuiSys/CFontImageDef.hpp"
#include "Runtime/GuiSys/CGuiSys.hpp"
#include "Runtime/GuiSys/CRasterFont.hpp"
#include "Runtime/GuiSys/CTextExecuteBuffer.hpp"
#include "Runtime/GuiSys/CTextParser.hpp"

namespace urde {

CGuiTextSupport::CGuiTextSupport(CAssetId fontId, const CGuiTextProperties& props, const zeus::CColor& fontCol,
                                 const zeus::CColor& outlineCol, const zeus::CColor& geomCol, s32 padX, s32 padY,
                                 CSimplePool* store, CGuiWidget::EGuiModelDrawFlags drawFlags)
: x14_props(props)
, x24_fontColor(fontCol)
, x28_outlineColor(outlineCol)
, x2c_geometryColor(geomCol)
, x34_extentX(padX)
, x38_extentY(padY)
, x5c_fontId(fontId)
, m_drawFlags(drawFlags) {
  x2cc_font = store->GetObj({SBIG('FONT'), fontId});
}

CTextRenderBuffer* CGuiTextSupport::GetCurrentPageRenderBuffer() {
  if (x60_renderBuf && !x308_multipageFlag) {
    return &*x60_renderBuf;
  }

  if (!x308_multipageFlag || x2ec_renderBufferPages.size() <= x304_pageCounter) {
    return nullptr;
  }

  int idx = 0;
  for (CTextRenderBuffer& buf : x2ec_renderBufferPages) {
    if (idx++ == x304_pageCounter) {
      return &buf;
    }
  }

  return nullptr;
}

const CTextRenderBuffer* CGuiTextSupport::GetCurrentPageRenderBuffer() const {
  if (x60_renderBuf && !x308_multipageFlag) {
    return &*x60_renderBuf;
  }

  if (!x308_multipageFlag || x2ec_renderBufferPages.size() <= x304_pageCounter) {
    return nullptr;
  }

  int idx = 0;
  for (const CTextRenderBuffer& buf : x2ec_renderBufferPages) {
    if (idx++ == x304_pageCounter) {
      return &buf;
    }
  }

  return nullptr;
}

float CGuiTextSupport::GetCurrentAnimationOverAge() const {
  float ret = 0.f;
  if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    if (x50_typeEnable) {
      if (x40_primStartTimes.size()) {
        auto& lastTime = x40_primStartTimes.back();
        ret = std::max(ret, (buf->GetPrimitiveCount() - lastTime.second) / x58_chRate + lastTime.first);
      } else {
        ret = std::max(ret, buf->GetPrimitiveCount() / x58_chRate);
      }
    }
  }
  return ret;
}

float CGuiTextSupport::GetNumCharsTotal() const {
  if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    if (x50_typeEnable) {
      return buf->GetPrimitiveCount();
    }
  }
  return 0.f;
}

float CGuiTextSupport::GetNumCharsPrinted() const {
  if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    if (x50_typeEnable) {
      const float charsPrinted = x3c_curTime * x58_chRate;
      return std::min(charsPrinted, float(buf->GetPrimitiveCount()));
    }
  }
  return 0.f;
}

float CGuiTextSupport::GetTotalAnimationTime() const {
  if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    if (x50_typeEnable) {
      return buf->GetPrimitiveCount() / x58_chRate;
    }
  }
  return 0.f;
}

bool CGuiTextSupport::IsAnimationDone() const { return x3c_curTime >= GetTotalAnimationTime(); }

void CGuiTextSupport::SetTypeWriteEffectOptions(bool enable, float chFadeTime, float chRate) {
  x50_typeEnable = enable;
  x54_chFadeTime = std::max(chFadeTime, 0.0001f);
  x58_chRate = std::max(chRate, 1.f);
  if (enable) {
    if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
      float chStartTime = 0.f;
      for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) {
        for (const std::pair<float, int>& p : x40_primStartTimes) {
          if (p.second < i)
            continue;
          if (p.second != i)
            break;
          chStartTime = p.first;
          break;
        }

        buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f));
        chStartTime += 1.f / x58_chRate;
      }
    }
  }
}

void CGuiTextSupport::Update(float dt) {
  if (x50_typeEnable) {
    if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
      float chStartTime = 0.f;
      for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) {
        for (const std::pair<float, int>& p : x40_primStartTimes) {
          if (p.second < i)
            continue;
          if (p.second != i)
            break;
          chStartTime = p.first;
          break;
        }

        buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f));
        chStartTime += 1.f / x58_chRate;
      }
    }
    x3c_curTime += dt;
  }

  x10_curTimeMod900 = std::fmod(x10_curTimeMod900 + dt, 900.f);
}

void CGuiTextSupport::ClearRenderBuffer() {
  x60_renderBuf = std::nullopt;
  x2ec_renderBufferPages.clear();
}

void CGuiTextSupport::CheckAndRebuildTextBuffer() {
  g_TextExecuteBuf->Clear();
  g_TextExecuteBuf->x18_textState.x7c_enableWordWrap = x14_props.x0_wordWrap;
  g_TextExecuteBuf->BeginBlock(0, 0, x34_extentX, x38_extentY, x30_imageBaseline,
                               ETextDirection(!x14_props.x1_horizontal), x14_props.x4_justification,
                               x14_props.x8_vertJustification);
  g_TextExecuteBuf->AddColor(EColorType::Main, x24_fontColor);
  g_TextExecuteBuf->AddColor(EColorType::Outline, x28_outlineColor);

  std::u16string initStr;
  if (x5c_fontId.IsValid())
    initStr = fmt::format(FMT_STRING(u"&font={};"), x5c_fontId);
  initStr += x0_string;

  g_TextParser->ParseText(*g_TextExecuteBuf, initStr.c_str(), initStr.size(), x14_props.xc_txtrMap);

  g_TextExecuteBuf->EndBlock();
}

bool CGuiTextSupport::CheckAndRebuildRenderBuffer() {
  if (x308_multipageFlag || x60_renderBuf)
    if (!x308_multipageFlag || x2ec_renderBufferPages.size())
      return true;

  CheckAndRebuildTextBuffer();
  x2bc_assets = g_TextExecuteBuf->GetAssets();

  if (!_GetIsTextSupportFinishedLoading())
    return false;

  CheckAndRebuildTextBuffer();
  if (x308_multipageFlag) {
    zeus::CVector2i extent(x34_extentX, x38_extentY);
    x2ec_renderBufferPages = g_TextExecuteBuf->BuildRenderBufferPages(extent, m_drawFlags);
  } else {
    x60_renderBuf.emplace(g_TextExecuteBuf->BuildRenderBuffer(m_drawFlags));
    x2dc_oneBufBounds = x60_renderBuf->AccumulateTextBounds();
  }
  g_TextExecuteBuf->Clear();
  Update(0.f);

  return true;
}

const std::pair<zeus::CVector2i, zeus::CVector2i>& CGuiTextSupport::GetBounds() {
  CheckAndRebuildRenderBuffer();
  return x2dc_oneBufBounds;
}

void CGuiTextSupport::AutoSetExtent() {
  const auto& bounds = GetBounds();
  x34_extentX = bounds.second.x;
  x38_extentY = bounds.second.y;
}

void CGuiTextSupport::Render() {
  CheckAndRebuildRenderBuffer();
  if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
    SCOPED_GRAPHICS_DEBUG_GROUP("CGuiTextSupport::Render", zeus::skBlue);
    zeus::CTransform oldModel = CGraphics::g_GXModelMatrix;
    CGraphics::SetModelMatrix(oldModel * zeus::CTransform::Scale(1.f, 1.f, -1.f));
    buf->Render(x2c_geometryColor, x10_curTimeMod900);
    CGraphics::SetModelMatrix(oldModel);
  }
}

void CGuiTextSupport::SetGeometryColor(const zeus::CColor& col) { x2c_geometryColor = col; }

void CGuiTextSupport::SetOutlineColor(const zeus::CColor& col) {
  if (col == x28_outlineColor) {
    return;
  }

  ClearRenderBuffer();
  x28_outlineColor = col;
}

void CGuiTextSupport::SetFontColor(const zeus::CColor& col) {
  if (col == x24_fontColor) {
    return;
  }

  ClearRenderBuffer();
  x24_fontColor = col;
}

void CGuiTextSupport::AddText(std::u16string_view str) {
  if (x60_renderBuf) {
    const float t = GetCurrentAnimationOverAge();
    x40_primStartTimes.emplace_back(std::max(t, x3c_curTime), x60_renderBuf->GetPrimitiveCount());
  }
  x0_string += str;
  ClearRenderBuffer();
}

void CGuiTextSupport::SetText(std::u16string_view str, bool multipage) {
  if (x0_string == str) {
    return;
  }

  x40_primStartTimes.clear();
  x3c_curTime = 0.f;
  x0_string = str;
  ClearRenderBuffer();
  x308_multipageFlag = multipage;
  x304_pageCounter = 0;
}

void CGuiTextSupport::SetText(std::string_view str, bool multipage) { SetText(hecl::UTF8ToChar16(str), multipage); }

bool CGuiTextSupport::_GetIsTextSupportFinishedLoading() {
  for (CToken& tok : x2bc_assets) {
    tok.Lock();

    if (!tok.IsLoaded()) {
      return false;
    }
  }

  if (!x2cc_font) {
    return true;
  }

  if (x2cc_font.IsLoaded()) {
    return x2cc_font->IsFinishedLoading();
  }

  return false;
}

void CGuiTextSupport::SetJustification(EJustification j) {
  if (j == x14_props.x4_justification) {
    return;
  }

  x14_props.x4_justification = j;
  ClearRenderBuffer();
}

void CGuiTextSupport::SetVerticalJustification(EVerticalJustification j) {
  if (j == x14_props.x8_vertJustification) {
    return;
  }

  x14_props.x8_vertJustification = j;
  ClearRenderBuffer();
}

void CGuiTextSupport::SetImageBaseline(bool b) {
  if (b == x30_imageBaseline) {
    return;
  }

  x30_imageBaseline = b;
  ClearRenderBuffer();
}

bool CGuiTextSupport::GetIsTextSupportFinishedLoading() {
  CheckAndRebuildRenderBuffer();
  return _GetIsTextSupportFinishedLoading();
}

void CGuiTextSupport::SetControlTXTRMap(const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  if (x14_props.xc_txtrMap == txtrMap) {
    return;
  }

  x14_props.xc_txtrMap = txtrMap;
  ClearRenderBuffer();
}

int CGuiTextSupport::GetTotalPageCount() {
  if (CheckAndRebuildRenderBuffer())
    return x2ec_renderBufferPages.size();
  return -1;
}

void CGuiTextSupport::SetPage(int page) {
  x304_pageCounter = page;
  x40_primStartTimes.clear();
  x3c_curTime = 0.f;
}

} // namespace urde
<|endoftext|>