<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.3  2000/02/06 07:47:58  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.2  1999/12/18 00:21:23  roddey
 * Fixed a small reported memory leak
 *
 * Revision 1.1.1.1  1999/11/09 01:07:47  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:45:02  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

#ifndef SAXEXCEPTION_HPP
#define SAXEXCEPTION_HPP

#include <util/XMLString.hpp>
#include <util/XMLUni.hpp>

/**
  * Encapsulate a general SAX error or warning.
  *
  *
This class can contain basic error or warning information from
  * either the XML SAX parser or the application: a parser writer or
  * application writer can subclass it to provide additional
  * functionality.  SAX handlers may throw this exception or
  * any exception subclassed from it.

  *
  *
If the application needs to pass through other types of
  * exceptions, it must wrap those exceptions in a SAXException
  * or an exception derived from a SAXException.

  *
  *
If the parser or application needs to include information
  * about a specific location in an XML document, it should use the
  * SAXParseException subclass.

  *
  * $Log$
  * Revision 1.3  2000/02/06 07:47:58  rahulj
  * Year 2K copyright swat.
  *
  * Revision 1.2  1999/12/18 00:21:23  roddey
  * Fixed a small reported memory leak
  *
  * Revision 1.1.1.1  1999/11/09 01:07:47  twl
  * Initial checkin
  *
  * Revision 1.2  1999/11/08 20:45:02  rahul
  * Swat for adding in Product name and CVS comment log variable.
  *
  * @see SAXParseException#SAXParseException
  */
class SAX_EXPORT SAXException
{
public:
    /** @name Constructors and Destructor */
    //@{
    /** Default constructor
     */
    SAXException() :

        fMsg(XMLString::replicate(XMLUni::fgZeroLenString))
    {
    }

  /**
    * Create a new SAXException.
    *
    * @param msg The error or warning message.
    */
    SAXException(const XMLCh* const msg) :

        fMsg(XMLString::replicate(msg))
    {
    }

    SAXException(const char* const msg) :

        fMsg(XMLString::transcode(msg))
    {
    }

    SAXException(const SAXException& toCopy) :

        fMsg(XMLString::replicate(toCopy.fMsg))
    {
    }

    /** Destructor */
    virtual ~SAXException()
    {
        delete [] fMsg;
    }

    //@}

    /** @name Public Operators */
    SAXException& operator=(const SAXException& toCopy)
    {
        if (this == &toCopy)
            return *this;

        delete [] fMsg;
        fMsg = XMLString::replicate(toCopy.fMsg);
        return *this;
    }

    /** @name Getter Methods */
    const XMLCh* getMessage() const
    {
        return fMsg;
    }

private :
    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fMsg
    //      This is the text of the error that is being thrown.
    // -----------------------------------------------------------------------
    XMLCh*  fMsg;
};

#endif
<commit_msg>Inserted documentation for new APIs<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.4  2000/02/09 19:15:17  abagchi
 * Inserted documentation for new APIs
 *
 * Revision 1.3  2000/02/06 07:47:58  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.2  1999/12/18 00:21:23  roddey
 * Fixed a small reported memory leak
 *
 * Revision 1.1.1.1  1999/11/09 01:07:47  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:45:02  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

#ifndef SAXEXCEPTION_HPP
#define SAXEXCEPTION_HPP

#include <util/XMLString.hpp>
#include <util/XMLUni.hpp>

/**
  * Encapsulate a general SAX error or warning.
  *
  *
This class can contain basic error or warning information from
  * either the XML SAX parser or the application: a parser writer or
  * application writer can subclass it to provide additional
  * functionality.  SAX handlers may throw this exception or
  * any exception subclassed from it.

  *
  *
If the application needs to pass through other types of
  * exceptions, it must wrap those exceptions in a SAXException
  * or an exception derived from a SAXException.

  *
  *
If the parser or application needs to include information
  * about a specific location in an XML document, it should use the
  * SAXParseException subclass.

  *
  * @see SAXParseException#SAXParseException
  */
class SAX_EXPORT SAXException
{
public:
    /** @name Constructors and Destructor */
    //@{
    /** Default constructor
     */
    SAXException() :

        fMsg(XMLString::replicate(XMLUni::fgZeroLenString))
    {
    }

  /**
    * Create a new SAXException.
    *
    * @param msg The error or warning message.
    */
    SAXException(const XMLCh* const msg) :

        fMsg(XMLString::replicate(msg))
    {
    }

  /**
    * Create a new SAXException.
    *
    * @param msg The error or warning message.
    */
    SAXException(const char* const msg) :

        fMsg(XMLString::transcode(msg))
    {
    }

  /**
    * Copy constructor
    *
    * @param toCopy The exception to be copy constructed
    */
    SAXException(const SAXException& toCopy) :

        fMsg(XMLString::replicate(toCopy.fMsg))
    {
    }

    /** Destructor */
    virtual ~SAXException()
    {
        delete [] fMsg;
    }

    //@}

    /** @name Public Operators */
    //@{
    /**
      * Assignment operator
      *
      * @param toCopy The object to be copied
      */
    SAXException& operator=(const SAXException& toCopy)
    {
        if (this == &toCopy)
            return *this;

        delete [] fMsg;
        fMsg = XMLString::replicate(toCopy.fMsg);
        return *this;
    }
    //@}

    /** @name Getter Methods */
    //@{
    /**
      * Get the contents of the message
      *
      */
    const XMLCh* getMessage() const
    {
        return fMsg;
    }
    //@}

private :
    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fMsg
    //      This is the text of the error that is being thrown.
    // -----------------------------------------------------------------------
    XMLCh*  fMsg;
};

#endif
<|endoftext|>


<commit_before>#include <pqxx/compiler.h>

#include <iostream>

#include <pqxx/binarystring>
#include <pqxx/connection>
#include <pqxx/transaction>
#include <pqxx/result>

using namespace PGSTD;
using namespace pqxx;

// Example program for libpqxx.  Test binarystring functionality.
//
// Usage: test062 [connect-string]
//
// Where connect-string is a set of connection options in Postgresql's
// PQconnectdb() format, eg. "dbname=template1" to select from a database
// called template1, or "host=foo.bar.net user=smith" to connect to a
// backend running on host foo.bar.net, logging in as user smith.

int main(int, char *argv[])
{
  try
  {
    const string TestStr =
      "Nasty\n\030Test\n\t String with \200\277 weird bytes "
      "\r\0 and Trailer\\\\\0";

    connection C(argv[1]);
    work T(C, "test62");

    T.exec("CREATE TEMP TABLE pqxxbin (binfield bytea)");
    const string Esc = escape_binary(TestStr);
    T.exec("INSERT INTO pqxxbin VALUES ('" + Esc + "')");

    result R = T.exec("SELECT * from pqxxbin");
    T.exec("DELETE FROM pqxxbin");

    binarystring B( R.at(0).at(0) );

    if (B.empty())
      throw logic_error("Binary string became empty in conversion");

    cout << "original: " << TestStr << endl
	 << "returned: " << B.c_ptr() << endl;

    if (B.size() != TestStr.size())
      throw logic_error("Binary string got changed from " +
	  to_string(TestStr.size()) + " to " + to_string(B.size()) + " bytes");

    binarystring::const_iterator c;
    binarystring::size_type i;
    for (i=0, c=B.begin(); i<B.size(); ++i, ++c)
    {
      if (c == B.end())
	throw logic_error("Premature end to binary string at " + to_string(i));

      const char x = TestStr.at(i), y = B.at(i);

      if (x != y)
      {
        const unsigned char ux = x, uy = y;
	const unsigned int uix = ux, uiy = uy;
	throw logic_error("Binary string byte " + to_string(i) + " "
	    "got changed from '" + to_string(x) + "' "
	    "(" + to_string(uix) + ") "
	    "to '" + to_string(y) + "' "
	    "(" + to_string(uiy) + ")");
      }
      if (y != B.data()[i])
	throw logic_error("Inconsistent byte at offset " + to_string(i) + ": "
	    "operator[] says '" + to_string(y) + "', "
	    "data() says '" + to_string(char(B.data()[i])) + "'");
    }
    if (B.at(0) != B.front())
      throw logic_error("Something wrong with binarystring::front()");
    if (c != B.end())
      throw logic_error("end() of binary string not reached");
    --c;
    if (*c != B.back())
      throw logic_error("Something wrong with binarystring::back()");

#ifdef PQXX_HAVE_REVERSE_ITERATOR
    binarystring::const_reverse_iterator r;
    for (i=B.length(), r=B.rbegin(); i>0; --i, ++r)
    {
      if (r == B.rend())
	throw logic_error("Premature rend to binary string at " + to_string(i));

      if (char(B[i-1]) != char(TestStr.at(i-1)))
	throw logic_error("Reverse iterator differs at " + to_string(i));
    }
    if (r != B.rend())
      throw logic_error("rend() of binary string not reached");
#endif

    if (B.str() != TestStr)
      throw logic_error("Binary string got mangled: '" + B.str() + "'");

    const string TestStr2("(More conventional text)");
    T.exec("INSERT INTO pqxxbin VALUES ('" + TestStr2 + "')");
    R = T.exec("SELECT * FROM pqxxbin");
    binarystring B2(R.front().front());

    if (B2 == B)
      throw logic_error("Two different binarystrings say they're equal!");
    if (!(B2 != B))
      throw logic_error("Problem with binarystring::operator!=");

    binarystring B1c(B), B2c(B2);
    if (B1c != B)
      throw logic_error("Copied binarystring differs from original");
    if (!(B2c == B2))
      throw logic_error("Copied binarystring not equal to original");

    B1c.swap(B2c);

    if (B2c == B1c)
      throw logic_error("Swapped binarystrings say they're identical!");
    if (B2c != B)
      throw logic_error("Problem with binarystring::swap()");
    if (!(B1c == B2))
      throw logic_error("Problem with one of two swapped binarystrings");
  }
  catch (const sql_error &e)
  {
    // If we're interested in the text of a failed query, we can write separate
    // exception handling code for this type of exception
    cerr << "SQL error: " << e.what() << endl
         << "Query was: '" << e.query() << "'" << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<commit_msg>Oops, works again<commit_after>#include <pqxx/compiler.h>

#include <iostream>

#include <pqxx/binarystring>
#include <pqxx/connection>
#include <pqxx/transaction>
#include <pqxx/result>

using namespace PGSTD;
using namespace pqxx;

// Example program for libpqxx.  Test binarystring functionality.
//
// Usage: test062 [connect-string]
//
// Where connect-string is a set of connection options in Postgresql's
// PQconnectdb() format, eg. "dbname=template1" to select from a database
// called template1, or "host=foo.bar.net user=smith" to connect to a
// backend running on host foo.bar.net, logging in as user smith.

int main(int, char *argv[])
{
  try
  {
    const string TestStr =
      "Nasty\n\030Test\n\t String with \200\277 weird bytes "
      "\r\0 and Trailer\\\\\0";

    connection C(argv[1]);
    work T(C, "test62");

    T.exec("CREATE TEMP TABLE pqxxbin (binfield bytea)");
    const string Esc = escape_binary(TestStr);
    T.exec("INSERT INTO pqxxbin VALUES ('" + Esc + "')");

    result R = T.exec("SELECT * from pqxxbin");
    T.exec("DELETE FROM pqxxbin");

    binarystring B( R.at(0).at(0) );

    if (B.empty())
      throw logic_error("Binary string became empty in conversion");

    cout << "original: " << TestStr << endl
	 << "returned: " << B.c_ptr() << endl;

    if (B.size() != TestStr.size())
      throw logic_error("Binary string got changed from " +
	  to_string(TestStr.size()) + " to " + to_string(B.size()) + " bytes");

    binarystring::const_iterator c;
    binarystring::size_type i;
    for (i=0, c=B.begin(); i<B.size(); ++i, ++c)
    {
      if (c == B.end())
	throw logic_error("Premature end to binary string at " + to_string(i));

      const char x = TestStr.at(i), y = B.at(i), z = B.data()[i];
      const unsigned char ux = x, uy = y, uz = z;
      const unsigned int uix = ux, uiy = uy, uiz = uz;

      if (x != y)
      {
	throw logic_error("Binary string byte " + to_string(i) + " "
	    "got changed from '" + to_string(x) + "' "
	    "(" + to_string(uix) + ") "
	    "to '" + to_string(y) + "' "
	    "(" + to_string(uiy) + ")");
      }

      if (y != z)
      {
	throw logic_error("Inconsistent byte at offset " + to_string(i) + ": "
	    "operator[] says '" + to_string(y) + "' (" + to_string(uiy) + "), "
	    "data() says '" + to_string(z) + "' "
	    "(" + to_string(uiz) + ")");
      }
    }
    if (B.at(0) != B.front())
      throw logic_error("Something wrong with binarystring::front()");
    if (c != B.end())
      throw logic_error("end() of binary string not reached");
    --c;
    if (*c != B.back())
      throw logic_error("Something wrong with binarystring::back()");

#ifdef PQXX_HAVE_REVERSE_ITERATOR
    binarystring::const_reverse_iterator r;
    for (i=B.length(), r=B.rbegin(); i>0; --i, ++r)
    {
      if (r == B.rend())
	throw logic_error("Premature rend to binary string at " + to_string(i));

      if (char(B[i-1]) != char(TestStr.at(i-1)))
	throw logic_error("Reverse iterator differs at " + to_string(i));
    }
    if (r != B.rend())
      throw logic_error("rend() of binary string not reached");
#endif

    if (B.str() != TestStr)
      throw logic_error("Binary string got mangled: '" + B.str() + "'");

    const string TestStr2("(More conventional text)");
    T.exec("INSERT INTO pqxxbin VALUES ('" + TestStr2 + "')");
    R = T.exec("SELECT * FROM pqxxbin");
    binarystring B2(R.front().front());

    if (B2 == B)
      throw logic_error("Two different binarystrings say they're equal!");
    if (!(B2 != B))
      throw logic_error("Problem with binarystring::operator!=");

    binarystring B1c(B), B2c(B2);
    if (B1c != B)
      throw logic_error("Copied binarystring differs from original");
    if (!(B2c == B2))
      throw logic_error("Copied binarystring not equal to original");

    B1c.swap(B2c);

    if (B2c == B1c)
      throw logic_error("Swapped binarystrings say they're identical!");
    if (B2c != B)
      throw logic_error("Problem with binarystring::swap()");
    if (!(B1c == B2))
      throw logic_error("Problem with one of two swapped binarystrings");
  }
  catch (const sql_error &e)
  {
    // If we're interested in the text of a failed query, we can write separate
    // exception handling code for this type of exception
    cerr << "SQL error: " << e.what() << endl
         << "Query was: '" << e.query() << "'" << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<|endoftext|>


<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

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

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <cassert>

#include "ingen/Log.hpp"
#include "ingen/URIs.hpp"
#include "ingen/World.hpp"
#include "raul/Maid.hpp"

#include "BlockImpl.hpp"
#include "BufferFactory.hpp"
#include "DuplexPort.hpp"
#include "EdgeImpl.hpp"
#include "Engine.hpp"
#include "GraphImpl.hpp"
#include "GraphPlugin.hpp"
#include "PortImpl.hpp"
#include "ThreadManager.hpp"

using namespace std;

namespace Ingen {
namespace Server {

GraphImpl::GraphImpl(Engine&             engine,
                     const Raul::Symbol& symbol,
                     uint32_t            poly,
                     GraphImpl*          parent,
                     SampleRate          srate,
                     uint32_t            internal_poly)
	: BlockImpl(new GraphPlugin(engine.world()->uris(),
	                            engine.world()->uris().ingen_Graph,
	                            Raul::Symbol("graph"),
	                            "Ingen Graph"),
	           symbol, poly, parent, srate)
	, _engine(engine)
	, _poly_pre(internal_poly)
	, _poly_process(internal_poly)
	, _compiled_graph(NULL)
	, _process(false)
{
	assert(internal_poly >= 1);
	assert(internal_poly <= 128);
}

GraphImpl::~GraphImpl()
{
	delete _compiled_graph;
	delete _plugin;
}

void
GraphImpl::activate(BufferFactory& bufs)
{
	BlockImpl::activate(bufs);

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		i->activate(bufs);
	}

	assert(_activated);
}

void
GraphImpl::deactivate()
{
	if (_activated) {
		BlockImpl::deactivate();

		for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
			if (i->activated()) {
				i->deactivate();
			}
		}
	}
}

void
GraphImpl::disable(ProcessContext& context)
{
	_process = false;
	for (Ports::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
		i->clear_buffers();
	}
}

bool
GraphImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	// TODO: Subgraph dynamic polyphony (i.e. changing port polyphony)

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		i->prepare_poly(bufs, poly);
	}

	_poly_pre = poly;
	return true;
}

bool
GraphImpl::apply_internal_poly(ProcessContext& context,
                               BufferFactory&  bufs,
                               Raul::Maid&     maid,
                               uint32_t        poly)
{
	// TODO: Subgraph dynamic polyphony (i.e. changing port polyphony)

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		i->apply_poly(context, maid, poly);
	}

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		for (uint32_t j = 0; j < i->num_ports(); ++j) {
			PortImpl* const port = i->port_impl(j);
			if (port->is_input() && dynamic_cast<InputPort*>(port)->direct_connect())
				port->setup_buffers(bufs, port->poly(), true);
			port->connect_buffers();
		}
	}

	const bool polyphonic = parent_graph() && (poly == parent_graph()->internal_poly_process());
	for (Ports::iterator i = _outputs.begin(); i != _outputs.end(); ++i)
		i->setup_buffers(bufs, polyphonic ? poly : 1, true);

	_poly_process = poly;
	return true;
}

/** Run the graph for the specified number of frames.
 *
 * Calls all Blocks in (roughly, if parallel) the order _compiled_graph specifies.
 */
void
GraphImpl::process(ProcessContext& context)
{
	if (!_process)
		return;

	BlockImpl::pre_process(context);

	if (_compiled_graph && _compiled_graph->size() > 0) {
		// Run all blocks
		for (size_t i = 0; i < _compiled_graph->size(); ++i) {
			(*_compiled_graph)[i].block()->process(context);
		}
	}

	BlockImpl::post_process(context);
}

void
GraphImpl::set_buffer_size(Context&       context,
                           BufferFactory& bufs,
                           LV2_URID       type,
                           uint32_t       size)
{
	BlockImpl::set_buffer_size(context, bufs, type, size);

	for (size_t i = 0; i < _compiled_graph->size(); ++i)
		(*_compiled_graph)[i].block()->set_buffer_size(context, bufs, type, size);
}

// Graph specific stuff

/** Add a block.
 * Preprocessing thread only.
 */
void
GraphImpl::add_block(BlockImpl& block)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);
	_blocks.push_front(block);
}

/** Remove a block.
 * Preprocessing thread only.
 */
void
GraphImpl::remove_block(BlockImpl& block)
{
	_blocks.erase(_blocks.iterator_to(block));
}

void
GraphImpl::add_edge(SharedPtr<EdgeImpl> c)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);
	_edges.insert(make_pair(make_pair(c->tail(), c->head()), c));
}

/** Remove a edge.
 * Preprocessing thread only.
 */
SharedPtr<EdgeImpl>
GraphImpl::remove_edge(const PortImpl* tail, const PortImpl* dst_port)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);
	Edges::iterator i = _edges.find(make_pair(tail, dst_port));
	if (i != _edges.end()) {
		SharedPtr<EdgeImpl> c = PtrCast<EdgeImpl>(i->second);
		_edges.erase(i);
		return c;
	} else {
		return SharedPtr<EdgeImpl>();
	}
}

bool
GraphImpl::has_edge(const PortImpl* tail, const PortImpl* dst_port) const
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);
	Edges::const_iterator i = _edges.find(make_pair(tail, dst_port));
	return (i != _edges.end());
}

void
GraphImpl::set_compiled_graph(CompiledGraph* cg)
{
	if (_compiled_graph && _compiled_graph != cg) {
		_engine.maid()->dispose(_compiled_graph);
	}
	_compiled_graph = cg;
}

uint32_t
GraphImpl::num_ports_non_rt() const
{
	ThreadManager::assert_not_thread(THREAD_PROCESS);
	return _inputs.size() + _outputs.size();
}

/** Create a port.  Not realtime safe.
 */
DuplexPort*
GraphImpl::create_port(BufferFactory&      bufs,
                       const Raul::Symbol& symbol,
                       PortType            type,
                       LV2_URID            buffer_type,
                       uint32_t            buffer_size,
                       bool                is_output,
                       bool                polyphonic)
{
	if (type == PortType::UNKNOWN) {
		bufs.engine().log().error(Raul::fmt("Unknown port type %1%\n")
		                          % type.uri());
		return NULL;
	}

	Raul::Atom value;
	if (type == PortType::CONTROL || type == PortType::CV)
		value = bufs.forge().make(0.0f);

	return new DuplexPort(bufs, this, symbol, num_ports_non_rt(), polyphonic, _polyphony,
	                      type, buffer_type, value, buffer_size, is_output);
}

/** Remove port from ports list used in pre-processing thread.
 *
 * Port is not removed from ports array for process thread (which could be
 * simultaneously running).
 *
 * Realtime safe.  Preprocessing thread only.
 */
void
GraphImpl::remove_port(DuplexPort& port)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	if (port.is_input()) {
		_inputs.erase(_inputs.iterator_to(port));
	} else {
		_outputs.erase(_outputs.iterator_to(port));
	}
}

/** Remove all ports from ports list used in pre-processing thread.
 *
 * Ports are not removed from ports array for process thread (which could be
 * simultaneously running).  Returned is a (inputs, outputs) pair.
 *
 * Realtime safe.  Preprocessing thread only.
 */
void
GraphImpl::clear_ports()
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	_inputs.clear();
	_outputs.clear();
}

Raul::Array<PortImpl*>*
GraphImpl::build_ports_array()
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	const size_t n = _inputs.size() + _outputs.size();
	Raul::Array<PortImpl*>* const result = new Raul::Array<PortImpl*>(n);

	size_t i = 0;

	for (Ports::iterator p = _inputs.begin(); p != _inputs.end(); ++p, ++i)
		result->at(i) = &*p;

	for (Ports::iterator p = _outputs.begin(); p != _outputs.end(); ++p, ++i)
		result->at(i) = &*p;

	assert(i == n);

	return result;
}

static inline void
compile_recursive(BlockImpl* n, CompiledGraph* output)
{
	if (n == NULL || n->traversed())
		return;

	n->traversed(true);
	assert(output != NULL);

	for (std::list<BlockImpl*>::iterator i = n->providers().begin();
	     i != n->providers().end(); ++i)
		if (!(*i)->traversed())
			compile_recursive(*i, output);

	output->push_back(CompiledBlock(n, n->providers().size(), n->dependants()));
}

/** Find the process order for this Graph.
 *
 * The process order is a flat list that the graph will execute in order
 * when its run() method is called.  Return value is a newly allocated list
 * which the caller is reponsible to delete.  Note that this function does
 * NOT actually set the process order, it is returned so it can be inserted
 * at the beginning of an audio cycle (by various Events).
 *
 * Not realtime safe.
 */
CompiledGraph*
GraphImpl::compile()
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	CompiledGraph* const compiled_graph = new CompiledGraph();

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		i->traversed(false);
	}

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		// Either a sink or connected to our output ports:
		if (!i->traversed() && i->dependants().empty()) {
			compile_recursive(&*i, compiled_graph);
		}
	}

	// Traverse any blocks we didn't hit yet
	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		if (!i->traversed()) {
			compile_recursive(&*i, compiled_graph);
		}
	}

	if (compiled_graph->size() != _blocks.size()) {
		_engine.log().error(Raul::fmt("Failed to compile graph %1%\n") % _path);
		delete compiled_graph;
		return NULL;
	}

	return compiled_graph;
}

} // namespace Server
} // namespace Ingen
<commit_msg>Fix crash when deleting subgraphs.<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

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

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <cassert>

#include "ingen/Log.hpp"
#include "ingen/URIs.hpp"
#include "ingen/World.hpp"
#include "raul/Maid.hpp"

#include "BlockImpl.hpp"
#include "BufferFactory.hpp"
#include "DuplexPort.hpp"
#include "EdgeImpl.hpp"
#include "Engine.hpp"
#include "GraphImpl.hpp"
#include "GraphPlugin.hpp"
#include "PortImpl.hpp"
#include "ThreadManager.hpp"

using namespace std;

namespace Ingen {
namespace Server {

GraphImpl::GraphImpl(Engine&             engine,
                     const Raul::Symbol& symbol,
                     uint32_t            poly,
                     GraphImpl*          parent,
                     SampleRate          srate,
                     uint32_t            internal_poly)
	: BlockImpl(new GraphPlugin(engine.world()->uris(),
	                            engine.world()->uris().ingen_Graph,
	                            Raul::Symbol("graph"),
	                            "Ingen Graph"),
	           symbol, poly, parent, srate)
	, _engine(engine)
	, _poly_pre(internal_poly)
	, _poly_process(internal_poly)
	, _compiled_graph(NULL)
	, _process(false)
{
	assert(internal_poly >= 1);
	assert(internal_poly <= 128);
}

GraphImpl::~GraphImpl()
{
	delete _compiled_graph;
	delete _plugin;
}

void
GraphImpl::activate(BufferFactory& bufs)
{
	BlockImpl::activate(bufs);

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		i->activate(bufs);
	}

	assert(_activated);
}

void
GraphImpl::deactivate()
{
	if (_activated) {
		BlockImpl::deactivate();

		for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
			if (i->activated()) {
				i->deactivate();
			}
		}
	}
}

void
GraphImpl::disable(ProcessContext& context)
{
	_process = false;
	for (Ports::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
		i->clear_buffers();
	}
}

bool
GraphImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	// TODO: Subgraph dynamic polyphony (i.e. changing port polyphony)

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		i->prepare_poly(bufs, poly);
	}

	_poly_pre = poly;
	return true;
}

bool
GraphImpl::apply_internal_poly(ProcessContext& context,
                               BufferFactory&  bufs,
                               Raul::Maid&     maid,
                               uint32_t        poly)
{
	// TODO: Subgraph dynamic polyphony (i.e. changing port polyphony)

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		i->apply_poly(context, maid, poly);
	}

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		for (uint32_t j = 0; j < i->num_ports(); ++j) {
			PortImpl* const port = i->port_impl(j);
			if (port->is_input() && dynamic_cast<InputPort*>(port)->direct_connect())
				port->setup_buffers(bufs, port->poly(), true);
			port->connect_buffers();
		}
	}

	const bool polyphonic = parent_graph() && (poly == parent_graph()->internal_poly_process());
	for (Ports::iterator i = _outputs.begin(); i != _outputs.end(); ++i)
		i->setup_buffers(bufs, polyphonic ? poly : 1, true);

	_poly_process = poly;
	return true;
}

/** Run the graph for the specified number of frames.
 *
 * Calls all Blocks in (roughly, if parallel) the order _compiled_graph specifies.
 */
void
GraphImpl::process(ProcessContext& context)
{
	if (!_process)
		return;

	BlockImpl::pre_process(context);

	if (_compiled_graph && _compiled_graph->size() > 0) {
		// Run all blocks
		for (size_t i = 0; i < _compiled_graph->size(); ++i) {
			(*_compiled_graph)[i].block()->process(context);
		}
	}

	BlockImpl::post_process(context);
}

void
GraphImpl::set_buffer_size(Context&       context,
                           BufferFactory& bufs,
                           LV2_URID       type,
                           uint32_t       size)
{
	BlockImpl::set_buffer_size(context, bufs, type, size);

	for (size_t i = 0; i < _compiled_graph->size(); ++i)
		(*_compiled_graph)[i].block()->set_buffer_size(context, bufs, type, size);
}

// Graph specific stuff

/** Add a block.
 * Preprocessing thread only.
 */
void
GraphImpl::add_block(BlockImpl& block)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);
	_blocks.push_front(block);
}

/** Remove a block.
 * Preprocessing thread only.
 */
void
GraphImpl::remove_block(BlockImpl& block)
{
	_blocks.erase(_blocks.iterator_to(block));
}

void
GraphImpl::add_edge(SharedPtr<EdgeImpl> c)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);
	_edges.insert(make_pair(make_pair(c->tail(), c->head()), c));
}

/** Remove a edge.
 * Preprocessing thread only.
 */
SharedPtr<EdgeImpl>
GraphImpl::remove_edge(const PortImpl* tail, const PortImpl* dst_port)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);
	Edges::iterator i = _edges.find(make_pair(tail, dst_port));
	if (i != _edges.end()) {
		SharedPtr<EdgeImpl> c = PtrCast<EdgeImpl>(i->second);
		_edges.erase(i);
		return c;
	} else {
		return SharedPtr<EdgeImpl>();
	}
}

bool
GraphImpl::has_edge(const PortImpl* tail, const PortImpl* dst_port) const
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);
	Edges::const_iterator i = _edges.find(make_pair(tail, dst_port));
	return (i != _edges.end());
}

void
GraphImpl::set_compiled_graph(CompiledGraph* cg)
{
	if (_compiled_graph && _compiled_graph != cg) {
		_engine.maid()->dispose(_compiled_graph);
	}
	_compiled_graph = cg;
}

uint32_t
GraphImpl::num_ports_non_rt() const
{
	ThreadManager::assert_not_thread(THREAD_PROCESS);
	return _inputs.size() + _outputs.size();
}

/** Create a port.  Not realtime safe.
 */
DuplexPort*
GraphImpl::create_port(BufferFactory&      bufs,
                       const Raul::Symbol& symbol,
                       PortType            type,
                       LV2_URID            buffer_type,
                       uint32_t            buffer_size,
                       bool                is_output,
                       bool                polyphonic)
{
	if (type == PortType::UNKNOWN) {
		bufs.engine().log().error(Raul::fmt("Unknown port type %1%\n")
		                          % type.uri());
		return NULL;
	}

	Raul::Atom value;
	if (type == PortType::CONTROL || type == PortType::CV)
		value = bufs.forge().make(0.0f);

	return new DuplexPort(bufs, this, symbol, num_ports_non_rt(), polyphonic, _polyphony,
	                      type, buffer_type, value, buffer_size, is_output);
}

/** Remove port from ports list used in pre-processing thread.
 *
 * Port is not removed from ports array for process thread (which could be
 * simultaneously running).
 *
 * Pre-processing thread or situations that won't cause races with it only.
 */
void
GraphImpl::remove_port(DuplexPort& port)
{
	if (port.is_input()) {
		_inputs.erase(_inputs.iterator_to(port));
	} else {
		_outputs.erase(_outputs.iterator_to(port));
	}
}

/** Remove all ports from ports list used in pre-processing thread.
 *
 * Ports are not removed from ports array for process thread (which could be
 * simultaneously running).  Returned is a (inputs, outputs) pair.
 *
 * Pre-processing thread or situations that won't cause races with it only.
 */
void
GraphImpl::clear_ports()
{
	_inputs.clear();
	_outputs.clear();
}

Raul::Array<PortImpl*>*
GraphImpl::build_ports_array()
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	const size_t n = _inputs.size() + _outputs.size();
	Raul::Array<PortImpl*>* const result = new Raul::Array<PortImpl*>(n);

	size_t i = 0;

	for (Ports::iterator p = _inputs.begin(); p != _inputs.end(); ++p, ++i)
		result->at(i) = &*p;

	for (Ports::iterator p = _outputs.begin(); p != _outputs.end(); ++p, ++i)
		result->at(i) = &*p;

	assert(i == n);

	return result;
}

static inline void
compile_recursive(BlockImpl* n, CompiledGraph* output)
{
	if (n == NULL || n->traversed())
		return;

	n->traversed(true);
	assert(output != NULL);

	for (std::list<BlockImpl*>::iterator i = n->providers().begin();
	     i != n->providers().end(); ++i)
		if (!(*i)->traversed())
			compile_recursive(*i, output);

	output->push_back(CompiledBlock(n, n->providers().size(), n->dependants()));
}

/** Find the process order for this Graph.
 *
 * The process order is a flat list that the graph will execute in order
 * when its run() method is called.  Return value is a newly allocated list
 * which the caller is reponsible to delete.  Note that this function does
 * NOT actually set the process order, it is returned so it can be inserted
 * at the beginning of an audio cycle (by various Events).
 *
 * Not realtime safe.
 */
CompiledGraph*
GraphImpl::compile()
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	CompiledGraph* const compiled_graph = new CompiledGraph();

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		i->traversed(false);
	}

	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		// Either a sink or connected to our output ports:
		if (!i->traversed() && i->dependants().empty()) {
			compile_recursive(&*i, compiled_graph);
		}
	}

	// Traverse any blocks we didn't hit yet
	for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
		if (!i->traversed()) {
			compile_recursive(&*i, compiled_graph);
		}
	}

	if (compiled_graph->size() != _blocks.size()) {
		_engine.log().error(Raul::fmt("Failed to compile graph %1%\n") % _path);
		delete compiled_graph;
		return NULL;
	}

	return compiled_graph;
}

} // namespace Server
} // namespace Ingen
<|endoftext|>


<commit_before>// ===============================
//  PC-BSD REST API Server
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> July 2015
// =================================
#include "WebServer.h"

#include <QCoreApplication>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QProcess>

#define DEBUG 0

#define PORTNUMBER 12142

#define APPCAFEWORKING QString("/var/tmp/appcafe/dispatch-queue.working")

//=======================
//              PUBLIC
//=======================
WebServer::WebServer() : QWebSocketServer("sysadm-server", QWebSocketServer::NonSecureMode){
  //Setup all the various settings
  //Any SSL changes
    /*QSslConfiguration ssl = this->sslConfiguration();
      ssl.setProtocol(QSsl::SecureProtocols);
    this->setSslConfiguration(ssl);*/
  AUTH = new AuthorizationManager();
  watcher = new QFileSystemWatcher(this);

  //Setup Connections
  connect(this, SIGNAL(closed()), this, SLOT(ServerClosed()) );
  connect(this, SIGNAL(serverError(QWebSocketProtocol::CloseCode)), this, SLOT(ServerError(QWebSocketProtocol::CloseCode)) );
  connect(this, SIGNAL(newConnection()), this, SLOT(NewSocketConnection()) );
  connect(this, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(NewConnectError(QAbstractSocket::SocketError)) );
  connect(this, SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*)), this, SLOT(OriginAuthRequired(QWebSocketCorsAuthenticator*)) );
  connect(this, SIGNAL(peerVerifyError(const QSslError&)), this, SLOT(PeerVerifyError(const QSslError&)) );
  connect(this, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(SslErrors(const QList<QSslError>&)) );
  connect(watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
  connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
}

WebServer::~WebServer(){
  delete AUTH;
}

bool WebServer::startServer(){
  bool ok = this->listen(QHostAddress::Any, PORTNUMBER);
  if(ok){
    QCoreApplication::processEvents();
    qDebug() << "Server Started:" << QDateTime::currentDateTime().toString(Qt::ISODate);
    qDebug() << " Name:" << this->serverName() << "Port:" << this->serverPort();
    qDebug() << " URL:" << this->serverUrl().toString() << "Remote Address:" << this->serverAddress().toString();
    if(!QFile::exists(APPCAFEWORKING)){ QProcess::execute("touch "+APPCAFEWORKING); }
    qDebug() << " Dispatcher Events:" << APPCAFEWORKING;
    watcher->addPath(APPCAFEWORKING);
    WatcherUpdate(APPCAFEWORKING); //load it initially
  }else{ qCritical() << "Could not start server - exiting..."; }
  return ok;
}

void WebServer::stopServer(){
  this->close();
}

//===================
//     PRIVATE
//===================
QString WebServer::generateID(){
  int id = 0;
  for(int i=0; i<OpenSockets.length(); i++){
    if(OpenSockets[i]->ID().toInt()>=id){ id = OpenSockets[i]->ID().toInt()+1; }
  }
  return QString::number(id);
}

QString WebServer::readFile(QString path){
  QFile file(path);
  if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ return ""; }
  QTextStream in(&file);
  QString contents = in.readAll();
  file.close();
  if(contents.endsWith("\n")){ contents.chop(1); }
  return contents;
}

//=======================
//       PRIVATE SLOTS
//=======================
// Overall Server signals
void WebServer::ServerClosed(){
  qDebug() << "Server Closed:" << QDateTime::currentDateTime().toString(Qt::ISODate);
  QCoreApplication::exit(0);
}

void WebServer::ServerError(QWebSocketProtocol::CloseCode code){
  qWarning() << "Server Error["+QString::number(code)+"]:" << this->errorString();
}

// New Connection Signals
void WebServer::NewSocketConnection(){
  if(!this->hasPendingConnections()){ return; }
  qDebug() << "New Socket Connection";
  //if(idletimer->isActive()){ idletimer->stop(); }
  QWebSocket *csock = this->nextPendingConnection();
  if(csock == 0){ qWarning() << " - new connection invalid, skipping..."; QTimer::singleShot(10, this, SLOT(NewSocketConnection())); return; }
  qDebug() <<  " - Accepting connection:" << csock->origin();
  WebSocket *sock = new WebSocket(csock, generateID(), AUTH);
  connect(sock, SIGNAL(SocketClosed(QString)), this, SLOT(SocketClosed(QString)) );
  connect(this, SIGNAL(DispatchStatusUpdate(QString)), sock, SLOT(AppCafeStatusUpdate(QString)) );
  sock->setLastDispatch(lastDispatch); //make sure this socket is aware of the latest notification
  OpenSockets << sock;
}

void WebServer::NewConnectError(QAbstractSocket::SocketError err){
  //if(csock!=0){
    //qWarning() << "New Connection Error["+QString::number(err)+"]:" << csock->errorString();
    //csock->close();
  //}else{
    qWarning() << "New Connection Error["+QString::number(err)+"]:" << this->errorString();
  //}
  //csock = 0; //remove the current socket
  QTimer::singleShot(0,this, SLOT(NewSocketConnection()) ); //check for a new connection

}

// SSL/Authentication Signals
void WebServer::OriginAuthRequired(QWebSocketCorsAuthenticator *auth){
  qDebug() << "Origin Auth Required:" << auth->origin();
  //if(auth->origin() == this->serverAddress().toString()){
  // TO-DO: Provide some kind of address filtering routine for which to accept/reject
    qDebug() << " - Allowed";
    auth->setAllowed(true);
  //}else{
    //qDebug() << " - Not Allowed";
    //auth->setAllowed(false);
  //}

}

void WebServer::PeerVerifyError(const QSslError &err){
  qDebug() << "Peer Verification Error:" << err.errorString();

}

void WebServer::SslErrors(const QList<QSslError> &list){
  qWarning() << "SSL Errors:";
  for(int i=0; i<list.length(); i++){
    qWarning() << " - " << list[i].errorString();
  }
}

void WebServer::SocketClosed(QString ID){
  for(int i=0; i<OpenSockets.length(); i++){
    if(OpenSockets[i]->ID()==ID){ delete OpenSockets.takeAt(i); break; }
  }
  QTimer::singleShot(0,this, SLOT(NewSocketConnection()) ); //check for a new connection
}

void WebServer::WatcherUpdate(QString path){
  if(path==APPCAFEWORKING){
    //Read the file contents
    QString stat = readFile(APPCAFEWORKING);
    if(stat.simplified().isEmpty()){ stat = "idle"; }
    qDebug() << "Dispatcher Update:" << stat;
    lastDispatch = stat; //save for later
    //Forward those contents on to the currently-open sockets
    emit DispatchStatusUpdate(stat);
  }
  //Make sure this file/dir is not removed from the watcher
  if(!watcher->files().contains(path) && !watcher->directories().contains(path)){
    watcher->addPath(path); //re-add it to the watcher. This happens when the file is removed/re-created instead of just overwritten
  }
}<commit_msg>Change port number to 12150<commit_after>// ===============================
//  PC-BSD REST API Server
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> July 2015
// =================================
#include "WebServer.h"

#include <QCoreApplication>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QProcess>

#define DEBUG 0

#define PORTNUMBER 12150

#define APPCAFEWORKING QString("/var/tmp/appcafe/dispatch-queue.working")

//=======================
//              PUBLIC
//=======================
WebServer::WebServer() : QWebSocketServer("sysadm-server", QWebSocketServer::NonSecureMode){
  //Setup all the various settings
  //Any SSL changes
    /*QSslConfiguration ssl = this->sslConfiguration();
      ssl.setProtocol(QSsl::SecureProtocols);
    this->setSslConfiguration(ssl);*/
  AUTH = new AuthorizationManager();
  watcher = new QFileSystemWatcher(this);

  //Setup Connections
  connect(this, SIGNAL(closed()), this, SLOT(ServerClosed()) );
  connect(this, SIGNAL(serverError(QWebSocketProtocol::CloseCode)), this, SLOT(ServerError(QWebSocketProtocol::CloseCode)) );
  connect(this, SIGNAL(newConnection()), this, SLOT(NewSocketConnection()) );
  connect(this, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(NewConnectError(QAbstractSocket::SocketError)) );
  connect(this, SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*)), this, SLOT(OriginAuthRequired(QWebSocketCorsAuthenticator*)) );
  connect(this, SIGNAL(peerVerifyError(const QSslError&)), this, SLOT(PeerVerifyError(const QSslError&)) );
  connect(this, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(SslErrors(const QList<QSslError>&)) );
  connect(watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
  connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(WatcherUpdate(QString)) );
}

WebServer::~WebServer(){
  delete AUTH;
}

bool WebServer::startServer(){
  bool ok = this->listen(QHostAddress::Any, PORTNUMBER);
  if(ok){
    QCoreApplication::processEvents();
    qDebug() << "Server Started:" << QDateTime::currentDateTime().toString(Qt::ISODate);
    qDebug() << " Name:" << this->serverName() << "Port:" << this->serverPort();
    qDebug() << " URL:" << this->serverUrl().toString() << "Remote Address:" << this->serverAddress().toString();
    if(!QFile::exists(APPCAFEWORKING)){ QProcess::execute("touch "+APPCAFEWORKING); }
    qDebug() << " Dispatcher Events:" << APPCAFEWORKING;
    watcher->addPath(APPCAFEWORKING);
    WatcherUpdate(APPCAFEWORKING); //load it initially
  }else{ qCritical() << "Could not start server - exiting..."; }
  return ok;
}

void WebServer::stopServer(){
  this->close();
}

//===================
//     PRIVATE
//===================
QString WebServer::generateID(){
  int id = 0;
  for(int i=0; i<OpenSockets.length(); i++){
    if(OpenSockets[i]->ID().toInt()>=id){ id = OpenSockets[i]->ID().toInt()+1; }
  }
  return QString::number(id);
}

QString WebServer::readFile(QString path){
  QFile file(path);
  if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ return ""; }
  QTextStream in(&file);
  QString contents = in.readAll();
  file.close();
  if(contents.endsWith("\n")){ contents.chop(1); }
  return contents;
}

//=======================
//       PRIVATE SLOTS
//=======================
// Overall Server signals
void WebServer::ServerClosed(){
  qDebug() << "Server Closed:" << QDateTime::currentDateTime().toString(Qt::ISODate);
  QCoreApplication::exit(0);
}

void WebServer::ServerError(QWebSocketProtocol::CloseCode code){
  qWarning() << "Server Error["+QString::number(code)+"]:" << this->errorString();
}

// New Connection Signals
void WebServer::NewSocketConnection(){
  if(!this->hasPendingConnections()){ return; }
  qDebug() << "New Socket Connection";
  //if(idletimer->isActive()){ idletimer->stop(); }
  QWebSocket *csock = this->nextPendingConnection();
  if(csock == 0){ qWarning() << " - new connection invalid, skipping..."; QTimer::singleShot(10, this, SLOT(NewSocketConnection())); return; }
  qDebug() <<  " - Accepting connection:" << csock->origin();
  WebSocket *sock = new WebSocket(csock, generateID(), AUTH);
  connect(sock, SIGNAL(SocketClosed(QString)), this, SLOT(SocketClosed(QString)) );
  connect(this, SIGNAL(DispatchStatusUpdate(QString)), sock, SLOT(AppCafeStatusUpdate(QString)) );
  sock->setLastDispatch(lastDispatch); //make sure this socket is aware of the latest notification
  OpenSockets << sock;
}

void WebServer::NewConnectError(QAbstractSocket::SocketError err){
  //if(csock!=0){
    //qWarning() << "New Connection Error["+QString::number(err)+"]:" << csock->errorString();
    //csock->close();
  //}else{
    qWarning() << "New Connection Error["+QString::number(err)+"]:" << this->errorString();
  //}
  //csock = 0; //remove the current socket
  QTimer::singleShot(0,this, SLOT(NewSocketConnection()) ); //check for a new connection

}

// SSL/Authentication Signals
void WebServer::OriginAuthRequired(QWebSocketCorsAuthenticator *auth){
  qDebug() << "Origin Auth Required:" << auth->origin();
  //if(auth->origin() == this->serverAddress().toString()){
  // TO-DO: Provide some kind of address filtering routine for which to accept/reject
    qDebug() << " - Allowed";
    auth->setAllowed(true);
  //}else{
    //qDebug() << " - Not Allowed";
    //auth->setAllowed(false);
  //}

}

void WebServer::PeerVerifyError(const QSslError &err){
  qDebug() << "Peer Verification Error:" << err.errorString();

}

void WebServer::SslErrors(const QList<QSslError> &list){
  qWarning() << "SSL Errors:";
  for(int i=0; i<list.length(); i++){
    qWarning() << " - " << list[i].errorString();
  }
}

void WebServer::SocketClosed(QString ID){
  for(int i=0; i<OpenSockets.length(); i++){
    if(OpenSockets[i]->ID()==ID){ delete OpenSockets.takeAt(i); break; }
  }
  QTimer::singleShot(0,this, SLOT(NewSocketConnection()) ); //check for a new connection
}

void WebServer::WatcherUpdate(QString path){
  if(path==APPCAFEWORKING){
    //Read the file contents
    QString stat = readFile(APPCAFEWORKING);
    if(stat.simplified().isEmpty()){ stat = "idle"; }
    qDebug() << "Dispatcher Update:" << stat;
    lastDispatch = stat; //save for later
    //Forward those contents on to the currently-open sockets
    emit DispatchStatusUpdate(stat);
  }
  //Make sure this file/dir is not removed from the watcher
  if(!watcher->files().contains(path) && !watcher->directories().contains(path)){
    watcher->addPath(path); //re-add it to the watcher. This happens when the file is removed/re-created instead of just overwritten
  }
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 1998 by Jorrit Tyberghein

    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; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "sysdef.h"
#include "qint.h"
#include "csengine/bsppol.h"
#include "csengine/polygon.h"

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

csPolygonBsp::csPolygonBsp ()
{
  max_vertices = 4;
  CHK (vertices = new csVector3 [max_vertices]);
  num_vertices = 0;
  poly3d = NULL;
}

csPolygonBsp::csPolygonBsp (csPolygon3D* orig_poly3d)
{
  max_vertices = num_vertices = orig_poly3d->GetNumVertices ();
  CHK (vertices = new csVector3 [max_vertices]);
  int i;
  for (i = 0 ; i < num_vertices ; i++)
    vertices[i] = orig_poly3d->Vwor (i);
  poly3d = orig_poly3d;
}

csPolygonBsp::~csPolygonBsp ()
{
  CHK (delete [] vertices);
}

void csPolygonBsp::AddVertex (const csVector3& v)
{
  if (num_vertices >= max_vertices)
  {
    max_vertices += 2;
    CHK (csVector3* new_vertices = new csVector3 [max_vertices]);
    memcpy (new_vertices, vertices, sizeof (csVector3)*num_vertices);
    CHK (delete [] vertices);
    vertices = new_vertices;
  }
  vertices[num_vertices++] = v;
}

int csPolygonBsp::Classify (csPolygonInt* spoly)
{
  if (SamePlane (spoly)) return POL_SAME_PLANE;

  int i;
  int front = 0, back = 0;
  csPolygonBsp* poly = (csPolygonBsp*)spoly;
  csPolyPlane* pl = poly->poly3d->GetPlane ();

  for (i = 0 ; i < num_vertices ; i++)
  {
    float dot = pl->Classify (vertices[i]);
    if (ABS (dot) < SMALL_EPSILON) dot = 0;
    if (dot > 0) back++;
    else if (dot < 0) front++;
  }
  if (back == 0) return POL_FRONT;
  if (front == 0) return POL_BACK;
  return POL_SPLIT_NEEDED;
}

void csPolygonBsp::SplitWithPlane (csPolygonInt** poly1, csPolygonInt** poly2,
				   csPlane& plane)
{
  CHK (csPolygonBsp* np1 = new csPolygonBsp ());
  CHK (csPolygonBsp* np2 = new csPolygonBsp ());
  *poly1 = (csPolygonInt*)np1; // Front
  *poly2 = (csPolygonInt*)np2; // Back
  np1->SetPolygon3D (poly3d);
  np2->SetPolygon3D (poly3d);

  csVector3 ptB;
  float sideA, sideB;
  csVector3 ptA = vertices[num_vertices - 1];
  sideA = plane.Classify (ptA);

  for (int i = -1 ; ++i < num_vertices ; )
  {
    ptB = vertices[i];
    sideB = plane.Classify (ptB);
    if (sideB > 0)
    {
      if (sideA < 0)
      {
	// Compute the intersection point of the line
	// from point A to point B with the partition
	// plane. This is a simple ray-plane intersection.
	csVector3 v = ptB; v -= ptA;
	float sect = - plane.Classify (ptA) / ( plane.Normal () * v ) ;
	v *= sect; v += ptA;
	np1->AddVertex (v);
	np2->AddVertex (v);
      }
      np2->AddVertex (ptB);
    }
    else if (sideB < 0)
    {
      if (sideA > 0)
      {
	// Compute the intersection point of the line
	// from point A to point B with the partition
	// plane. This is a simple ray-plane intersection.
	csVector3 v = ptB; v -= ptA;
	float sect = - plane.Classify (ptA) / ( plane.Normal () * v );
	v *= sect; v += ptA;
	np1->AddVertex (v);
	np2->AddVertex (v);
      }
      np1->AddVertex (ptB);
    }
    else
    {
      np1->AddVertex (ptB);
      np2->AddVertex (ptB);
    }
    ptA = ptB;
    sideA = sideB;
  }
}

bool csPolygonBsp::SamePlane (csPolygonInt* p)
{
  if (((csPolygonBsp*)p)->GetPolyPlane () == GetPolyPlane ()) return true;
  return csMath3::PlanesEqual (*((csPolygonBsp*)p)->GetPolyPlane (), *GetPolyPlane ());
}

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

csPolygonBspContainer::csPolygonBspContainer ()
{
  max_polygon = 10;
  CHK (polygons = new csPolygonInt* [max_polygon]);
  num_polygon = 0;
}

csPolygonBspContainer::~csPolygonBspContainer ()
{
  if (polygons)
  {
    for (int i = 0 ; i < num_polygon ; i++)
      CHKB (delete (csPolygonBsp*)polygons [i]);
    CHK (delete [] polygons);
  }
}

void csPolygonSet::AddPolygon (csPolygonInt* poly)
{
  if (num_polygon >= max_polygon)
  {
    max_polygon += 10;
    CHK (csPolygonInt** new_polygons = new csPolygonInt* [max_polygon]);
    memcpy (new_polygons, polygons, sizeof (csPolygonInt*)*num_polygon);
    CHK (delete [] polygons);
    polygons = new_polygons;
  }

  polygons[num_polygon++] = poly;
}

//---------------------------------------------------------------------------
<commit_msg>Renamed csPolygonSet::AddPolygon into csPolygonBspContainer::AddPolygon as this cleanly was Jorrit's mistake, besides I've got duplicate symbol problems<commit_after>/*
    Copyright (C) 1998 by Jorrit Tyberghein

    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; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "sysdef.h"
#include "qint.h"
#include "csengine/bsppol.h"
#include "csengine/polygon.h"

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

csPolygonBsp::csPolygonBsp ()
{
  max_vertices = 4;
  CHK (vertices = new csVector3 [max_vertices]);
  num_vertices = 0;
  poly3d = NULL;
}

csPolygonBsp::csPolygonBsp (csPolygon3D* orig_poly3d)
{
  max_vertices = num_vertices = orig_poly3d->GetNumVertices ();
  CHK (vertices = new csVector3 [max_vertices]);
  int i;
  for (i = 0 ; i < num_vertices ; i++)
    vertices[i] = orig_poly3d->Vwor (i);
  poly3d = orig_poly3d;
}

csPolygonBsp::~csPolygonBsp ()
{
  CHK (delete [] vertices);
}

void csPolygonBsp::AddVertex (const csVector3& v)
{
  if (num_vertices >= max_vertices)
  {
    max_vertices += 2;
    CHK (csVector3* new_vertices = new csVector3 [max_vertices]);
    memcpy (new_vertices, vertices, sizeof (csVector3)*num_vertices);
    CHK (delete [] vertices);
    vertices = new_vertices;
  }
  vertices[num_vertices++] = v;
}

int csPolygonBsp::Classify (csPolygonInt* spoly)
{
  if (SamePlane (spoly)) return POL_SAME_PLANE;

  int i;
  int front = 0, back = 0;
  csPolygonBsp* poly = (csPolygonBsp*)spoly;
  csPolyPlane* pl = poly->poly3d->GetPlane ();

  for (i = 0 ; i < num_vertices ; i++)
  {
    float dot = pl->Classify (vertices[i]);
    if (ABS (dot) < SMALL_EPSILON) dot = 0;
    if (dot > 0) back++;
    else if (dot < 0) front++;
  }
  if (back == 0) return POL_FRONT;
  if (front == 0) return POL_BACK;
  return POL_SPLIT_NEEDED;
}

void csPolygonBsp::SplitWithPlane (csPolygonInt** poly1, csPolygonInt** poly2,
				   csPlane& plane)
{
  CHK (csPolygonBsp* np1 = new csPolygonBsp ());
  CHK (csPolygonBsp* np2 = new csPolygonBsp ());
  *poly1 = (csPolygonInt*)np1; // Front
  *poly2 = (csPolygonInt*)np2; // Back
  np1->SetPolygon3D (poly3d);
  np2->SetPolygon3D (poly3d);

  csVector3 ptB;
  float sideA, sideB;
  csVector3 ptA = vertices[num_vertices - 1];
  sideA = plane.Classify (ptA);

  for (int i = -1 ; ++i < num_vertices ; )
  {
    ptB = vertices[i];
    sideB = plane.Classify (ptB);
    if (sideB > 0)
    {
      if (sideA < 0)
      {
	// Compute the intersection point of the line
	// from point A to point B with the partition
	// plane. This is a simple ray-plane intersection.
	csVector3 v = ptB; v -= ptA;
	float sect = - plane.Classify (ptA) / ( plane.Normal () * v ) ;
	v *= sect; v += ptA;
	np1->AddVertex (v);
	np2->AddVertex (v);
      }
      np2->AddVertex (ptB);
    }
    else if (sideB < 0)
    {
      if (sideA > 0)
      {
	// Compute the intersection point of the line
	// from point A to point B with the partition
	// plane. This is a simple ray-plane intersection.
	csVector3 v = ptB; v -= ptA;
	float sect = - plane.Classify (ptA) / ( plane.Normal () * v );
	v *= sect; v += ptA;
	np1->AddVertex (v);
	np2->AddVertex (v);
      }
      np1->AddVertex (ptB);
    }
    else
    {
      np1->AddVertex (ptB);
      np2->AddVertex (ptB);
    }
    ptA = ptB;
    sideA = sideB;
  }
}

bool csPolygonBsp::SamePlane (csPolygonInt* p)
{
  if (((csPolygonBsp*)p)->GetPolyPlane () == GetPolyPlane ()) return true;
  return csMath3::PlanesEqual (*((csPolygonBsp*)p)->GetPolyPlane (), *GetPolyPlane ());
}

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

csPolygonBspContainer::csPolygonBspContainer ()
{
  max_polygon = 10;
  CHK (polygons = new csPolygonInt* [max_polygon]);
  num_polygon = 0;
}

csPolygonBspContainer::~csPolygonBspContainer ()
{
  if (polygons)
  {
    for (int i = 0 ; i < num_polygon ; i++)
      CHKB (delete (csPolygonBsp*)polygons [i]);
    CHK (delete [] polygons);
  }
}

void csPolygonBspContainer::AddPolygon (csPolygonInt* poly)
{
  if (num_polygon >= max_polygon)
  {
    max_polygon += 10;
    CHK (csPolygonInt** new_polygons = new csPolygonInt* [max_polygon]);
    memcpy (new_polygons, polygons, sizeof (csPolygonInt*)*num_polygon);
    CHK (delete [] polygons);
    polygons = new_polygons;
  }

  polygons[num_polygon++] = poly;
}

//---------------------------------------------------------------------------
<|endoftext|>


<commit_before>/*
    Crystal Space utility library: string class
    Copyright (C) 1999,2000 by Andrew Zabolotny <bit@eltech.ru>

    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; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

extern "C" {
#include <ctype.h>
#include <stdarg.h>
}
#include "cssysdef.h"
#include "csutil/csstring.h"
#include "csutil/snprintf.h"

csString::~csString ()
{
  Free ();
}

void csString::Free ()
{
  delete[] Data;
  Data = NULL;
  Size = 0;
  MaxSize = 0;
}

void csString::SetCapacity (size_t NewSize)
{
  NewSize++; // Plus one for implicit null byte.
  if (NewSize <= MaxSize)
    return;
  MaxSize = NewSize;
  char* buff = new char[MaxSize];
  if (Data == 0 || Size == 0)
    buff[0] = '\0';
  else
    memcpy(buff, Data, Size + 1);

  if (Data)
    delete[] Data;
  Data = buff;
}

void csString::ExpandIfNeeded(size_t NewSize)
{
  if (NewSize + 1 > MaxSize)
  {
    size_t n;
    if (!GrowExponentially)
      n = (NewSize + GrowBy - 1) & ~(GrowBy - 1);
    else
    {
      n = MaxSize != 0 ? MaxSize << 1 : size_t(DEFAULT_GROW_BY);
      while (n < NewSize)
        n <<= 1;
    }
    SetCapacity(n);
  }
}

void csString::SetGrowsBy(size_t n)
{
  if (n < DEFAULT_GROW_BY)
    n = DEFAULT_GROW_BY;
  // Round `n' up to multiple of DEFAULT_GROW_BY.
  GrowBy = (n + DEFAULT_GROW_BY - 1) & ~(DEFAULT_GROW_BY - 1);
  GrowExponentially = false;
}

csString &csString::Reclaim()
{
  if (Size == 0)
    Free();
  else
  {
    CS_ASSERT(Data != 0);
    MaxSize = Size + 1; // Plus one for implicit null byte.
    char* s = new char[MaxSize];
    memcpy(s, Data, MaxSize);
    delete[] Data;
    Data = s;
  }
  return *this;
}

csString &csString::Truncate (size_t iPos)
{
  if (iPos < Size)
  {
    Size = iPos;
    Data [Size] = '\0';
  }
  return *this;
}

csString &csString::DeleteAt (size_t iPos, size_t iCount)
{
  CS_ASSERT (iPos < Size && iPos + iCount <= Size);

  if (iPos + iCount < Size)
    memmove(Data + iPos, Data + iPos + iCount, Size - (iPos + iCount));
  Size -= iCount;
  Data[Size] = '\0';
  return *this;
}

csString &csString::Insert (size_t iPos, const csString &iStr)
{
  CS_ASSERT(iPos <= Size);

  if (Data == 0 || iPos == Size)
    return Append (iStr);

  size_t const sl = iStr.Length ();
  size_t const NewSize = sl + Size;
  ExpandIfNeeded (NewSize);
  memmove (Data + iPos + sl, Data + iPos, Size - iPos + 1); // Also move null.
  memcpy (Data + iPos, iStr.GetData (), sl);
  Size = NewSize;
  return *this;
}

csString &csString::Insert (size_t iPos, const char iChar)
{
  csString s(iChar);
  return Insert(iPos, s);
}

csString &csString::Overwrite (size_t iPos, const csString &iStr)
{
  CS_ASSERT (iPos <= Size);

  if (Data == 0 || iPos == Size)
    return Append (iStr);

  size_t const sl = iStr.Length ();
  size_t const NewSize = iPos + sl;
  ExpandIfNeeded (NewSize);
  memcpy (Data + iPos, iStr.GetData (), sl + 1); // Also copy null terminator.
  Size = NewSize;
  return *this;
}

csString &csString::Append (const csString &iStr, size_t iCount)
{
  return Append(iStr.GetData(), iCount);
}

csString &csString::Append (const char *iStr, size_t iCount)
{
  if (iStr == 0)
    return *this;
  if (iCount == (size_t)-1)
    iCount = strlen (iStr);

  // We're not aborting here if iCount==0, because Replace is using it in a
  // not fully correct way: Size=0; Append(str);

  size_t const NewSize = Size + iCount;
  ExpandIfNeeded (NewSize);

  if (iCount > 0)
      memcpy (Data + Size, iStr, iCount);

  Size = NewSize;
  Data [Size] = '\0';
  return *this;
}

csString &csString::LTrim()
{
  size_t i;
  for (i = 0; i < Size; i++)
    if (!isspace (Data[i]))
      break;
  if (i > 0)
    DeleteAt (0, i);
  return *this;
}

csString &csString::RTrim()
{
  if (Size > 0)
  {
    int i;
    for (i = Size - 1; i >= 0; i--)
      if (!isspace (Data[i]))
        break;
    if (i < int(Size - 1))
      Truncate(i + 1);
  }
  return *this;
}

csString &csString::Trim()
{
  return LTrim().RTrim();
}

csString &csString::Collapse()
{
  if (Size > 0)
  {
    char const* src = Data;
    char const* slim = Data + Size;
    char* dst = Data;
    bool saw_white = false;
    for ( ; src < slim; src++)
    {
      char const c = *src;
      if (isspace(c))
        saw_white = true;
      else
      {
        if (saw_white && dst > Data)
          *dst++ = ' ';
        *dst++ = c;
        saw_white = false;
      }
    }
    Size = dst - Data;
    Data[Size] = '\0';
  }
  return *this;
}

csString &csString::FormatV (const char *format, va_list args)
{
  if (Data == 0) // Ensure that backing-store exists prior to vsnprintf().
    SetCapacity(255);

  int rc = 0;
  while (1)
  {
    rc = cs_vsnprintf(Data, MaxSize, format, args);
    // Buffer was big enough for entire string?
    if (rc >= 0 && rc < (int)MaxSize)
      break;
    // Some vsnprintf()s return -1 on failure, others return desired capacity.
    if (rc >= 0)
      SetCapacity(rc); // SetCapacity() ensures room for null byte.
    else
      SetCapacity(MaxSize * 2);
  }
  Size = rc;
  return *this;
}

csString &csString::Format (const char *format, ...)
{
  va_list args;
  va_start (args, format);

  FormatV (format, args);

  va_end (args);
  return *this;
}

#define STR_FORMAT(TYPE,FMT,SZ) \
csString csString::Format (TYPE v) \
{ char s[SZ]; cs_snprintf (s, SZ, #FMT, v); return csString ().Append (s); }
  STR_FORMAT(short, %hd, 32)
  STR_FORMAT(unsigned short, %hu, 32)
  STR_FORMAT(int, %d, 32)
  STR_FORMAT(unsigned int, %u, 32)
  STR_FORMAT(long, %ld, 32)
  STR_FORMAT(unsigned long, %lu, 32)
  STR_FORMAT(float, %g, 64)
  STR_FORMAT(double, %g, 64)
#undef STR_FORMAT

#define STR_FORMAT_INT(TYPE,FMT) \
csString csString::Format (TYPE v, int width, int prec/*=0*/) \
{ char s[64], s1[64]; \
  cs_snprintf (s1, sizeof(s1), "%%%d.%d"#FMT, width, prec); \
  cs_snprintf (s, sizeof(s), s1, v); \
  return csString ().Append (s); }
  STR_FORMAT_INT(short, hd)
  STR_FORMAT_INT(unsigned short, hu)
  STR_FORMAT_INT(int, d)
  STR_FORMAT_INT(unsigned int, u)
  STR_FORMAT_INT(long, ld)
  STR_FORMAT_INT(unsigned long, lu)
#undef STR_FORMAT_INT

#define STR_FORMAT_FLOAT(TYPE) \
csString csString::Format (TYPE v, int width, int prec/*=6*/) \
{ char s[64], s1[64]; \
  cs_snprintf (s1, sizeof(s1), "%%%d.%dg", width, prec); \
  cs_snprintf (s, sizeof(s), s1, v); \
  return csString ().Append (s); }
  STR_FORMAT_FLOAT(float)
  STR_FORMAT_FLOAT(double)
#undef STR_FORMAT_FLOAT

csString &csString::PadLeft (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    ExpandIfNeeded (iNewSize);
    const size_t toInsert = iNewSize - Size;
    memmove (Data + toInsert, Data, Size + 1); // Also move null terminator.
    for (size_t x = 0; x < toInsert; x++)
      Data [x] = iChar;
    Size = iNewSize;
  }
  return *this;
}

csString csString::AsPadLeft (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadLeft (iChar, iNewSize);
  return newStr;
}

#define STR_PADLEFT(TYPE) \
csString csString::PadLeft (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadLeft (iNewSize, iChar); }
  STR_PADLEFT(const csString&)
  STR_PADLEFT(const char*)
  STR_PADLEFT(char)
  STR_PADLEFT(unsigned char)
  STR_PADLEFT(short)
  STR_PADLEFT(unsigned short)
  STR_PADLEFT(int)
  STR_PADLEFT(unsigned int)
  STR_PADLEFT(long)
  STR_PADLEFT(unsigned long)
  STR_PADLEFT(float)
  STR_PADLEFT(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADLEFT(bool)
#endif
#undef STR_PADLEFT

csString& csString::PadRight (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    ExpandIfNeeded (iNewSize);
    for (size_t x = Size; x < iNewSize; x++)
      Data [x] = iChar;
    Size = iNewSize;
    Data [Size] = '\0';
  }
  return *this;
}

csString csString::AsPadRight (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadRight (iChar, iNewSize);
  return newStr;
}

#define STR_PADRIGHT(TYPE) \
csString csString::PadRight (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadRight (iNewSize, iChar); }
  STR_PADRIGHT(const csString&)
  STR_PADRIGHT(const char*)
  STR_PADRIGHT(char)
  STR_PADRIGHT(unsigned char)
  STR_PADRIGHT(short)
  STR_PADRIGHT(unsigned short)
  STR_PADRIGHT(int)
  STR_PADRIGHT(unsigned int)
  STR_PADRIGHT(long)
  STR_PADRIGHT(unsigned long)
  STR_PADRIGHT(float)
  STR_PADRIGHT(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADRIGHT(bool)
#endif
#undef STR_PADRIGHT

csString& csString::PadCenter (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    ExpandIfNeeded (iNewSize);
    const size_t toInsert = iNewSize - Size;
    const size_t halfInsert = toInsert / 2;
    if (Size > 0)
      memmove (Data + halfInsert, Data, Size);
    size_t x;
    for (x = 0; x < halfInsert; x++)
      Data [x] = iChar;
    for (x = halfInsert + Size; x < iNewSize; x++)
      Data [x] = iChar;
    Size = iNewSize;
    Data [Size] = '\0';
  }
  return *this;
}

csString csString::AsPadCenter (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadCenter (iChar, iNewSize);
  return newStr;
}

#define STR_PADCENTER(TYPE) \
csString csString::PadCenter (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadCenter (iNewSize, iChar); }
  STR_PADCENTER(const csString&)
  STR_PADCENTER(const char*)
  STR_PADCENTER(char)
  STR_PADCENTER(unsigned char)
  STR_PADCENTER(short)
  STR_PADCENTER(unsigned short)
  STR_PADCENTER(int)
  STR_PADCENTER(unsigned int)
  STR_PADCENTER(long)
  STR_PADCENTER(unsigned long)
  STR_PADCENTER(float)
  STR_PADCENTER(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADCENTER(bool)
#endif
#undef STR_PADCENTER
<commit_msg>	- fixed MSVC assertion in csString::Collapse() if the string 	  contains characters >= 0x80<commit_after>/*
    Crystal Space utility library: string class
    Copyright (C) 1999,2000 by Andrew Zabolotny <bit@eltech.ru>

    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; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

extern "C" {
#include <ctype.h>
#include <stdarg.h>
}
#include "cssysdef.h"
#include "csutil/csstring.h"
#include "csutil/snprintf.h"

csString::~csString ()
{
  Free ();
}

void csString::Free ()
{
  delete[] Data;
  Data = NULL;
  Size = 0;
  MaxSize = 0;
}

void csString::SetCapacity (size_t NewSize)
{
  NewSize++; // Plus one for implicit null byte.
  if (NewSize <= MaxSize)
    return;
  MaxSize = NewSize;
  char* buff = new char[MaxSize];
  if (Data == 0 || Size == 0)
    buff[0] = '\0';
  else
    memcpy(buff, Data, Size + 1);

  if (Data)
    delete[] Data;
  Data = buff;
}

void csString::ExpandIfNeeded(size_t NewSize)
{
  if (NewSize + 1 > MaxSize)
  {
    size_t n;
    if (!GrowExponentially)
      n = (NewSize + GrowBy - 1) & ~(GrowBy - 1);
    else
    {
      n = MaxSize != 0 ? MaxSize << 1 : size_t(DEFAULT_GROW_BY);
      while (n < NewSize)
        n <<= 1;
    }
    SetCapacity(n);
  }
}

void csString::SetGrowsBy(size_t n)
{
  if (n < DEFAULT_GROW_BY)
    n = DEFAULT_GROW_BY;
  // Round `n' up to multiple of DEFAULT_GROW_BY.
  GrowBy = (n + DEFAULT_GROW_BY - 1) & ~(DEFAULT_GROW_BY - 1);
  GrowExponentially = false;
}

csString &csString::Reclaim()
{
  if (Size == 0)
    Free();
  else
  {
    CS_ASSERT(Data != 0);
    MaxSize = Size + 1; // Plus one for implicit null byte.
    char* s = new char[MaxSize];
    memcpy(s, Data, MaxSize);
    delete[] Data;
    Data = s;
  }
  return *this;
}

csString &csString::Truncate (size_t iPos)
{
  if (iPos < Size)
  {
    Size = iPos;
    Data [Size] = '\0';
  }
  return *this;
}

csString &csString::DeleteAt (size_t iPos, size_t iCount)
{
  CS_ASSERT (iPos < Size && iPos + iCount <= Size);

  if (iPos + iCount < Size)
    memmove(Data + iPos, Data + iPos + iCount, Size - (iPos + iCount));
  Size -= iCount;
  Data[Size] = '\0';
  return *this;
}

csString &csString::Insert (size_t iPos, const csString &iStr)
{
  CS_ASSERT(iPos <= Size);

  if (Data == 0 || iPos == Size)
    return Append (iStr);

  size_t const sl = iStr.Length ();
  size_t const NewSize = sl + Size;
  ExpandIfNeeded (NewSize);
  memmove (Data + iPos + sl, Data + iPos, Size - iPos + 1); // Also move null.
  memcpy (Data + iPos, iStr.GetData (), sl);
  Size = NewSize;
  return *this;
}

csString &csString::Insert (size_t iPos, const char iChar)
{
  csString s(iChar);
  return Insert(iPos, s);
}

csString &csString::Overwrite (size_t iPos, const csString &iStr)
{
  CS_ASSERT (iPos <= Size);

  if (Data == 0 || iPos == Size)
    return Append (iStr);

  size_t const sl = iStr.Length ();
  size_t const NewSize = iPos + sl;
  ExpandIfNeeded (NewSize);
  memcpy (Data + iPos, iStr.GetData (), sl + 1); // Also copy null terminator.
  Size = NewSize;
  return *this;
}

csString &csString::Append (const csString &iStr, size_t iCount)
{
  return Append(iStr.GetData(), iCount);
}

csString &csString::Append (const char *iStr, size_t iCount)
{
  if (iStr == 0)
    return *this;
  if (iCount == (size_t)-1)
    iCount = strlen (iStr);

  // We're not aborting here if iCount==0, because Replace is using it in a
  // not fully correct way: Size=0; Append(str);

  size_t const NewSize = Size + iCount;
  ExpandIfNeeded (NewSize);

  if (iCount > 0)
      memcpy (Data + Size, iStr, iCount);

  Size = NewSize;
  Data [Size] = '\0';
  return *this;
}

csString &csString::LTrim()
{
  size_t i;
  for (i = 0; i < Size; i++)
    if (!isspace (Data[i]))
      break;
  if (i > 0)
    DeleteAt (0, i);
  return *this;
}

csString &csString::RTrim()
{
  if (Size > 0)
  {
    int i;
    for (i = Size - 1; i >= 0; i--)
      if (!isspace (Data[i]))
        break;
    if (i < int(Size - 1))
      Truncate(i + 1);
  }
  return *this;
}

csString &csString::Trim()
{
  return LTrim().RTrim();
}

csString &csString::Collapse()
{
  if (Size > 0)
  {
    char const* src = Data;
    char const* slim = Data + Size;
    char* dst = Data;
    bool saw_white = false;
    for ( ; src < slim; src++)
    {
      // if c is signed char isspace() may trigger an
      // assertion for chars >= 0x80
      unsigned char const c = *src;
      if (isspace(c))
        saw_white = true;
      else
      {
        if (saw_white && dst > Data)
          *dst++ = ' ';
        *dst++ = c;
        saw_white = false;
      }
    }
    Size = dst - Data;
    Data[Size] = '\0';
  }
  return *this;
}

csString &csString::FormatV (const char *format, va_list args)
{
  if (Data == 0) // Ensure that backing-store exists prior to vsnprintf().
    SetCapacity(255);

  int rc = 0;
  while (1)
  {
    rc = cs_vsnprintf(Data, MaxSize, format, args);
    // Buffer was big enough for entire string?
    if (rc >= 0 && rc < (int)MaxSize)
      break;
    // Some vsnprintf()s return -1 on failure, others return desired capacity.
    if (rc >= 0)
      SetCapacity(rc); // SetCapacity() ensures room for null byte.
    else
      SetCapacity(MaxSize * 2);
  }
  Size = rc;
  return *this;
}

csString &csString::Format (const char *format, ...)
{
  va_list args;
  va_start (args, format);

  FormatV (format, args);

  va_end (args);
  return *this;
}

#define STR_FORMAT(TYPE,FMT,SZ) \
csString csString::Format (TYPE v) \
{ char s[SZ]; cs_snprintf (s, SZ, #FMT, v); return csString ().Append (s); }
  STR_FORMAT(short, %hd, 32)
  STR_FORMAT(unsigned short, %hu, 32)
  STR_FORMAT(int, %d, 32)
  STR_FORMAT(unsigned int, %u, 32)
  STR_FORMAT(long, %ld, 32)
  STR_FORMAT(unsigned long, %lu, 32)
  STR_FORMAT(float, %g, 64)
  STR_FORMAT(double, %g, 64)
#undef STR_FORMAT

#define STR_FORMAT_INT(TYPE,FMT) \
csString csString::Format (TYPE v, int width, int prec/*=0*/) \
{ char s[64], s1[64]; \
  cs_snprintf (s1, sizeof(s1), "%%%d.%d"#FMT, width, prec); \
  cs_snprintf (s, sizeof(s), s1, v); \
  return csString ().Append (s); }
  STR_FORMAT_INT(short, hd)
  STR_FORMAT_INT(unsigned short, hu)
  STR_FORMAT_INT(int, d)
  STR_FORMAT_INT(unsigned int, u)
  STR_FORMAT_INT(long, ld)
  STR_FORMAT_INT(unsigned long, lu)
#undef STR_FORMAT_INT

#define STR_FORMAT_FLOAT(TYPE) \
csString csString::Format (TYPE v, int width, int prec/*=6*/) \
{ char s[64], s1[64]; \
  cs_snprintf (s1, sizeof(s1), "%%%d.%dg", width, prec); \
  cs_snprintf (s, sizeof(s), s1, v); \
  return csString ().Append (s); }
  STR_FORMAT_FLOAT(float)
  STR_FORMAT_FLOAT(double)
#undef STR_FORMAT_FLOAT

csString &csString::PadLeft (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    ExpandIfNeeded (iNewSize);
    const size_t toInsert = iNewSize - Size;
    memmove (Data + toInsert, Data, Size + 1); // Also move null terminator.
    for (size_t x = 0; x < toInsert; x++)
      Data [x] = iChar;
    Size = iNewSize;
  }
  return *this;
}

csString csString::AsPadLeft (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadLeft (iChar, iNewSize);
  return newStr;
}

#define STR_PADLEFT(TYPE) \
csString csString::PadLeft (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadLeft (iNewSize, iChar); }
  STR_PADLEFT(const csString&)
  STR_PADLEFT(const char*)
  STR_PADLEFT(char)
  STR_PADLEFT(unsigned char)
  STR_PADLEFT(short)
  STR_PADLEFT(unsigned short)
  STR_PADLEFT(int)
  STR_PADLEFT(unsigned int)
  STR_PADLEFT(long)
  STR_PADLEFT(unsigned long)
  STR_PADLEFT(float)
  STR_PADLEFT(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADLEFT(bool)
#endif
#undef STR_PADLEFT

csString& csString::PadRight (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    ExpandIfNeeded (iNewSize);
    for (size_t x = Size; x < iNewSize; x++)
      Data [x] = iChar;
    Size = iNewSize;
    Data [Size] = '\0';
  }
  return *this;
}

csString csString::AsPadRight (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadRight (iChar, iNewSize);
  return newStr;
}

#define STR_PADRIGHT(TYPE) \
csString csString::PadRight (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadRight (iNewSize, iChar); }
  STR_PADRIGHT(const csString&)
  STR_PADRIGHT(const char*)
  STR_PADRIGHT(char)
  STR_PADRIGHT(unsigned char)
  STR_PADRIGHT(short)
  STR_PADRIGHT(unsigned short)
  STR_PADRIGHT(int)
  STR_PADRIGHT(unsigned int)
  STR_PADRIGHT(long)
  STR_PADRIGHT(unsigned long)
  STR_PADRIGHT(float)
  STR_PADRIGHT(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADRIGHT(bool)
#endif
#undef STR_PADRIGHT

csString& csString::PadCenter (size_t iNewSize, char iChar)
{
  if (iNewSize > Size)
  {
    ExpandIfNeeded (iNewSize);
    const size_t toInsert = iNewSize - Size;
    const size_t halfInsert = toInsert / 2;
    if (Size > 0)
      memmove (Data + halfInsert, Data, Size);
    size_t x;
    for (x = 0; x < halfInsert; x++)
      Data [x] = iChar;
    for (x = halfInsert + Size; x < iNewSize; x++)
      Data [x] = iChar;
    Size = iNewSize;
    Data [Size] = '\0';
  }
  return *this;
}

csString csString::AsPadCenter (size_t iNewSize, char iChar)
{
  csString newStr = Clone ();
  newStr.PadCenter (iChar, iNewSize);
  return newStr;
}

#define STR_PADCENTER(TYPE) \
csString csString::PadCenter (TYPE v, size_t iNewSize, char iChar) \
{ csString newStr; return newStr.Append (v).PadCenter (iNewSize, iChar); }
  STR_PADCENTER(const csString&)
  STR_PADCENTER(const char*)
  STR_PADCENTER(char)
  STR_PADCENTER(unsigned char)
  STR_PADCENTER(short)
  STR_PADCENTER(unsigned short)
  STR_PADCENTER(int)
  STR_PADCENTER(unsigned int)
  STR_PADCENTER(long)
  STR_PADCENTER(unsigned long)
  STR_PADCENTER(float)
  STR_PADCENTER(double)
#if !defined(CS_USE_FAKE_BOOL_TYPE)
  STR_PADCENTER(bool)
#endif
#undef STR_PADCENTER
<|endoftext|>