<commit_before>#include "BetaMath.h"

namespace RandMath {

long double logBeta(double a, double b)
{
    if (a <= 0 || b <= 0)
        return NAN;
    bool aIsInteger = areClose(a, std::round(a));
    bool bIsInteger = areClose(b, std::round(b));
    long double lgammaA = aIsInteger ? lfact(a - 1) : std::lgammal(a);
    long double lgammaB = lgammaA;
    if (a != b)
        lgammaB = bIsInteger ? lfact(b - 1) : std::lgammal(b);
    long double lgammaApB = (bIsInteger && bIsInteger) ? lfact(a + b - 1) : std::lgammal(a + b);
    return lgammaA + lgammaB - lgammaApB;
}

long double beta(double a, double b)
{
    return std::exp(logBeta(a, b));
}

double ibetaPowerSeries1(double x, double a, double b, double logBetaFun, double logX, double log1mX)
{
    double addon = 1.0, sum = 0.0;
    /// avoid underflow
    double u = (x > 1e-5) ? -x / (1.0 - x) : -std::exp(logX - log1mX);
    int n = 1;
    do {
        addon *= (n - b) * u / (a + n);
        sum += addon;
        ++n;
    } while (std::fabs(addon) > MIN_POSITIVE * std::fabs(sum));
    double y = a * logX;
    y += (b - 1) * log1mX;
    y -= logBetaFun;
    y += std::log1p(sum);
    return std::exp(y) / a;
}

double ibetacontinuedFraction1(double x, double a, double b, int number, double logBetaFun, double logX, double log1mX)
{
    int n = number;
    /// avoid underflow
    double u = (x > 1e-5) ? x / (1.0 - x) : std::exp(logX - log1mX);
    double frac = 0.0;
    while (n > 1) {
        double cn = (b - n + 1) / (a + n - 1) * u;
        frac = cn / (1 + cn - frac);
        --n;
    }
    double c1 = b / a;
    double F = c1 / (1 + c1 - frac);
    double y = a * logX;
    y += (b - 1) * log1mX;
    y -= logBetaFun;
    y = std::exp(y) / b;
    y *= F / (1.0 - F);
    return y;
}

double ibetaPowerSeries2(double x, double a, double b, double logBetaFun, double logX, double log1mX)
{
    double addon = 1.0, sum = 0.0;
    int n = 0;
    do {
        addon *= (n + a + b) * x / (a + n + 1);
        sum += addon;
        ++n;
    } while (std::fabs(addon) > MIN_POSITIVE * std::fabs(sum));
    double y = a * logX;
    y += b * log1mX;
    y -= logBetaFun;
    y += std::log1p(sum);
    return std::exp(y) / a;
}

double ibetaContinuedFraction2(double x, double a, double b, int number, double logBetaFun, double logX, double log1mX)
{
    int n = number;
    double frac = 0.0;
    while (n > 1) {
        double cn = (a + b + n - 2) / (a + n - 1) * x;
        frac = cn / (1 + cn - frac);
        --n;
    }
    double c1 = (a + b - 1) / a;
    double F = c1 / (1 + c1 - frac);
    double y = a * logX;
    y += b * log1mX;
    y -= logBetaFun;
    y = std::exp(y) / (a + b - 1);
    y *= F / (1.0 - F);
    return y;
}

double ibeta(double x, double a, double b, double logBetaFun, double logX, double log1mX)
{
    /// Check special values
    if (a <= 0 || b <= 0 || x < 0.0 || x > 1.0)
        return NAN;
    if (x == 0.0)
        return 0.0;
    if (x == 1.0)
        return 1.0;
    if (b == 1.0)
        return std::exp(a * logX);
    if (a == 1.0)
        return -std::expm1(b * log1mX);

    /// If x is larger than mean of Beta distribution,
    /// convergence of complementary distribution function is faster
    if (x > a / (a + b))
        return 1.0 - ibeta(1.0 - x, b, a);

    /// We truncate after 0.45 instead of 0.5 here
    /// in order to avoid x being too close to 0.5
    if (x < 0.45) {
        if (b < 1)
            return ibetaPowerSeries1(x, a, b, logBetaFun, logX, log1mX);
        double number = std::floor(b);
        /// equivalent continued fraction #1
        double ecd = ibetacontinuedFraction1(x, a, b, number, logBetaFun, logX, log1mX);
        double apn = a + number, bmn = b - number;
        double residue = (b == number) ? 0.0 : ibetaPowerSeries1(x, apn, bmn, logBeta(apn, bmn), logX, log1mX);
        return ecd + residue;
    }

    if (b < 1)
        return ibetaPowerSeries2(x, a, b, logBetaFun, logX, log1mX);
    double number = std::floor(b);
    /// equivalent continued fraction #2
    double ecd = ibetaContinuedFraction2(x, a, b, number, logBetaFun, logX, log1mX);
    double apn = a + number;
    double residue = ibetaPowerSeries2(x, apn, b, logBeta(apn, b), logX, log1mX);
    return ecd + residue;
}

double ibeta(double x, double a, double b)
{
    /// Check special values
    if (a <= 0 || b <= 0 || x < 0.0 || x > 1.0)
        return NAN;
    if (x == 0.0)
        return 0.0;
    if (x == 1.0)
        return 1.0;
    if (b == 1.0)
        return std::pow(x, a);
    if (a == 1.0) {
        double y = b * std::log1p(-x);
        return -std::expm1(y);
    }
    double logBetaFun = logBeta(a, b);
    double logX = std::log(x), log1mX = std::log1p(-x);
    return ibeta(x, a, b, logBetaFun, logX, log1mX);
}

}
<commit_msg>Update BetaMath.cpp<commit_after>#include "BetaMath.h"

namespace RandMath {

long double logBeta(double a, double b)
{
    if (a <= 0 || b <= 0)
        return NAN;
    bool aIsInteger = areClose(a, std::round(a));
    bool bIsInteger = areClose(b, std::round(b));
    long double lgammaA = aIsInteger ? lfact(a - 1) : std::lgammal(a);
    long double lgammaB = lgammaA;
    if (a != b)
        lgammaB = bIsInteger ? lfact(b - 1) : std::lgammal(b);
    long double lgammaApB = (aIsInteger && bIsInteger) ? lfact(a + b - 1) : std::lgammal(a + b);
    return lgammaA + lgammaB - lgammaApB;
}

long double beta(double a, double b)
{
    return std::exp(logBeta(a, b));
}

double ibetaPowerSeries1(double x, double a, double b, double logBetaFun, double logX, double log1mX)
{
    double addon = 1.0, sum = 0.0;
    /// avoid underflow
    double u = (x > 1e-5) ? -x / (1.0 - x) : -std::exp(logX - log1mX);
    int n = 1;
    do {
        addon *= (n - b) * u / (a + n);
        sum += addon;
        ++n;
    } while (std::fabs(addon) > MIN_POSITIVE * std::fabs(sum));
    double y = a * logX;
    y += (b - 1) * log1mX;
    y -= logBetaFun;
    y += std::log1p(sum);
    return std::exp(y) / a;
}

double ibetacontinuedFraction1(double x, double a, double b, int number, double logBetaFun, double logX, double log1mX)
{
    int n = number;
    /// avoid underflow
    double u = (x > 1e-5) ? x / (1.0 - x) : std::exp(logX - log1mX);
    double frac = 0.0;
    while (n > 1) {
        double cn = (b - n + 1) / (a + n - 1) * u;
        frac = cn / (1 + cn - frac);
        --n;
    }
    double c1 = b / a;
    double F = c1 / (1 + c1 - frac);
    double y = a * logX;
    y += (b - 1) * log1mX;
    y -= logBetaFun;
    y = std::exp(y) / b;
    y *= F / (1.0 - F);
    return y;
}

double ibetaPowerSeries2(double x, double a, double b, double logBetaFun, double logX, double log1mX)
{
    double addon = 1.0, sum = 0.0;
    int n = 0;
    do {
        addon *= (n + a + b) * x / (a + n + 1);
        sum += addon;
        ++n;
    } while (std::fabs(addon) > MIN_POSITIVE * std::fabs(sum));
    double y = a * logX;
    y += b * log1mX;
    y -= logBetaFun;
    y += std::log1p(sum);
    return std::exp(y) / a;
}

double ibetaContinuedFraction2(double x, double a, double b, int number, double logBetaFun, double logX, double log1mX)
{
    int n = number;
    double frac = 0.0;
    while (n > 1) {
        double cn = (a + b + n - 2) / (a + n - 1) * x;
        frac = cn / (1 + cn - frac);
        --n;
    }
    double c1 = (a + b - 1) / a;
    double F = c1 / (1 + c1 - frac);
    double y = a * logX;
    y += b * log1mX;
    y -= logBetaFun;
    y = std::exp(y) / (a + b - 1);
    y *= F / (1.0 - F);
    return y;
}

double ibeta(double x, double a, double b, double logBetaFun, double logX, double log1mX)
{
    /// Check special values
    if (a <= 0 || b <= 0 || x < 0.0 || x > 1.0)
        return NAN;
    if (x == 0.0)
        return 0.0;
    if (x == 1.0)
        return 1.0;
    if (b == 1.0)
        return std::exp(a * logX);
    if (a == 1.0)
        return -std::expm1(b * log1mX);

    /// If x is larger than mean of Beta distribution,
    /// convergence of complementary distribution function is faster
    if (x > a / (a + b))
        return 1.0 - ibeta(1.0 - x, b, a);

    /// We truncate after 0.45 instead of 0.5 here
    /// in order to avoid x being too close to 0.5
    if (x < 0.45) {
        if (b < 1)
            return ibetaPowerSeries1(x, a, b, logBetaFun, logX, log1mX);
        double number = std::floor(b);
        /// equivalent continued fraction #1
        double ecd = ibetacontinuedFraction1(x, a, b, number, logBetaFun, logX, log1mX);
        double apn = a + number, bmn = b - number;
        double residue = (b == number) ? 0.0 : ibetaPowerSeries1(x, apn, bmn, logBeta(apn, bmn), logX, log1mX);
        return ecd + residue;
    }

    if (b < 1)
        return ibetaPowerSeries2(x, a, b, logBetaFun, logX, log1mX);
    double number = std::floor(b);
    /// equivalent continued fraction #2
    double ecd = ibetaContinuedFraction2(x, a, b, number, logBetaFun, logX, log1mX);
    double apn = a + number;
    double residue = ibetaPowerSeries2(x, apn, b, logBeta(apn, b), logX, log1mX);
    return ecd + residue;
}

double ibeta(double x, double a, double b)
{
    /// Check special values
    if (a <= 0 || b <= 0 || x < 0.0 || x > 1.0)
        return NAN;
    if (x == 0.0)
        return 0.0;
    if (x == 1.0)
        return 1.0;
    if (b == 1.0)
        return std::pow(x, a);
    if (a == 1.0) {
        double y = b * std::log1p(-x);
        return -std::expm1(y);
    }
    double logBetaFun = logBeta(a, b);
    double logX = std::log(x), log1mX = std::log1p(-x);
    return ibeta(x, a, b, logBetaFun, logX, log1mX);
}

}
<|endoftext|>


<commit_before>/**
 * @file Scalar.hpp
 *
 * Defines conversion of matrix to scalar.
 *
 * @author James Goppert <james.goppert@gmail.com>
 */

#pragma once

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "math.hpp"

namespace matrix
{

template<typename Type>
class Scalar
{
public:
    virtual ~Scalar() {};

    Scalar() : _value()
    {
    }

    Scalar(const Matrix<Type, 1, 1> & other)
    {
        _value = other(0,0);
    }

    Scalar(Type other)
    {
        _value = other;
    }

    operator Type &()
    {
        return _value;
    }

    operator Type const &() const
    {
        return _value;
    }

    operator Matrix<Type, 1, 1>() const {
        Matrix<Type, 1, 1> m;
        m(0, 0) = _value;
        return m;
    }

private:
    Type _value;

};

typedef Scalar<float> Scalarf;

} // namespace matrix

/* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */
<commit_msg>Added conversion for scalar to vector.<commit_after>/**
 * @file Scalar.hpp
 *
 * Defines conversion of matrix to scalar.
 *
 * @author James Goppert <james.goppert@gmail.com>
 */

#pragma once

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "math.hpp"

namespace matrix
{

template<typename Type>
class Scalar
{
public:
    virtual ~Scalar() {};

    Scalar() : _value()
    {
    }

    Scalar(const Matrix<Type, 1, 1> & other)
    {
        _value = other(0,0);
    }

    Scalar(Type other)
    {
        _value = other;
    }

    operator Type &()
    {
        return _value;
    }

    operator Type const &() const
    {
        return _value;
    }

    operator Matrix<Type, 1, 1>() const {
        Matrix<Type, 1, 1> m;
        m(0, 0) = _value;
        return m;
    }

    operator Vector<Type, 1>() const {
        Vector<Type, 1> m;
        m(0) = _value;
        return m;
    }

private:
    Type _value;

};

typedef Scalar<float> Scalarf;

} // namespace matrix

/* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */
<|endoftext|>


<commit_before>/****************** <SNX heading BEGIN do not edit this line> *****************
 *
 * sonix
 *
 * Original Authors:
 *   Kevin Meinert
 *
 * -----------------------------------------------------------------
 * File:          $RCSfile$
 * Date modified: $Date$
 * Version:       $Revision$
 * -----------------------------------------------------------------
 *
 ****************** <SNX heading END do not edit this line> ******************/

/*************** <auto-copyright.pl BEGIN do not edit this line> **************
 *
 * VR Juggler is (C) Copyright 1998-2003 by Iowa State University
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 *************** <auto-copyright.pl END do not edit this line> ***************/

#include <snx/snxConfig.h>

#include <iostream>
#include <fstream>
#include <string>

#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/operations.hpp>

#include <vpr/vpr.h>
#include <vpr/System.h>
#include <vpr/Util/FileUtils.h>
#include <vpr/DynLoad/LibraryFinder.h>

#include <snx/Util/Debug.h>
#include "snx/ISoundImplementation.h"
#include "snx/StubSoundImplementation.h" // in case lookup fails...

#include "snx/SoundFactory.h" // my header.

namespace snx
{

/**
 * Create the plugin.
 * Symbol name to look up from the shared lib is "newPlugin".
 */
typedef snx::ISoundImplementation* (*newPluginFunc)(void);

/**
 * Gets the name of the plugin.
 * Symbol name to lookup from the shared lib is "getName".
 */
typedef char* (*getNameFunc)(void);

/**
 * Get the version of sonix plugin was compiled against.
 * Symbol name to lookup from the shared lib is "getVersion".
 */
typedef char* (*getVersionFunc)(void);

vprSingletonImp(SoundFactory);

SoundFactory::SoundFactory()
{
   std::vector<std::string> search_paths;

   const std::string envvar("SNX_BASE_DIR");
   std::string dummy_result;

   if ( vpr::System::getenv(envvar, dummy_result).failure() )
   {
      vprDEBUG(snxDBG, vprDBG_WARNING_LVL)
         << clrOutBOLD(clrYELLOW, "WARNING:")
         << " SNX_BASE_DIR environment variable not set!\n" << vprDEBUG_FLUSH;
      vprDEBUG_NEXT(snxDBG, vprDBG_WARNING_LVL)
         << "Plug-in loading may fail.\n" << vprDEBUG_FLUSH;
   }

#if defined(_ABIN32)
   std::string snx_lib_dir("${SNX_BASE_DIR}/lib32/snx/plugins");
#elif defined(_ABI64)
   std::string snx_lib_dir("${SNX_BASE_DIR}/lib64/snx/plugins");
#else
   std::string snx_lib_dir("${SNX_BASE_DIR}/lib/snx/plugins");
#endif

#ifdef SNX_DEBUG
   snx_lib_dir += std::string("/dbg");
#else
   snx_lib_dir += std::string("/opt");
#endif

#if defined(VPR_OS_Win32)
   const std::string driver_ext("dll");
#elif defined(VPR_OS_Darwin)
   const std::string driver_ext("dylib");
#else
   const std::string driver_ext("so");
#endif

   search_paths.push_back(snx_lib_dir);
   search_paths.push_back( "${HOME}/.sonix/plugins" );

   for (unsigned int x = 0; x < search_paths.size(); ++x)
   {
      search_paths[x] = vpr::replaceEnvVars(search_paths[x]);
      vprDEBUG(snxDBG, vprDBG_CONFIG_LVL) << "Finding plugins in "
                                          << search_paths[x] << std::endl
                                          << vprDEBUG_FLUSH;

      boost::filesystem::path dirPath(search_paths[x]);
      if (boost::filesystem::exists(dirPath))
      {
         vpr::LibraryFinder finder(search_paths[x], driver_ext);
         vpr::LibraryFinder::LibraryList libs = finder.getLibraries();
         this->loadPlugins( libs );

#ifdef SNX_DEBUG
         vprDEBUG(snxDBG, vprDBG_CONFIG_LVL) << "filelist:\n" << vprDEBUG_FLUSH;
         for ( unsigned int i = 0; i < libs.size(); ++i )
         {
            vprDEBUG(snxDBG, vprDBG_CONFIG_LVL) << "\t" << libs[i]
                                                << std::endl << vprDEBUG_FLUSH;
         }
#endif
      }
      else
      {
         vprDEBUG(snxDBG, vprDBG_STATE_LVL)
            << "The directory does not exist: '" << search_paths[x] << "'\n"
            << vprDEBUG_FLUSH;
      }
   }
}

void SoundFactory::errorOutput(vpr::LibraryPtr lib, const char* test)
{
   vprDEBUG(snxDBG, vprDBG_WARNING_LVL)
      << "ERROR: Plugin '" << lib->getName() << "' does not export symbol '"
      << test << "'\n" << vprDEBUG_FLUSH;
}

bool SoundFactory::isPlugin(vpr::LibraryPtr lib)
{
   if (lib->findSymbol( "newPlugin" ) == NULL)
   {
      errorOutput(lib, "newPlugin");
      return false;
   }
   if (lib->findSymbol( "getVersion" ) == NULL)
   {
      errorOutput(lib, "getVersion");
      return false;
   }
   if (lib->findSymbol( "getName" ) == NULL)
   {
      errorOutput(lib, "getName");
      return false;
   }

   // @todo give sonix an internal version number string!
   //getVersionFunc getVersion = (getVersionFunc)lib.lookup( "getVersion" );
   //if (getVersion != NULL && getVersion() != snx::version) return false;
   vprDEBUG(snxDBG, vprDBG_CONFIG_STATUS_LVL) << "Plugin '" << lib->getName()
                                              << "' is a valid Sonix plugin.\n"
                                              << vprDEBUG_FLUSH;
   return true;
}

void SoundFactory::loadPlugins( vpr::LibraryFinder::LibraryList libs )
{
   for (unsigned int x = 0; x < libs.size(); ++x)
   {
      // open the library
      vpr::ReturnStatus didLoad = libs[x]->load();

      if (didLoad == vpr::ReturnStatus::Succeed)
      {
        //If the plug-in implements the nessiasry interface
        if ( this->isPlugin(libs[x]) )
        {
            // get the name..
            getNameFunc getName = (getNameFunc)libs[x]->findSymbol( "getName" );
            std::string name;
            if (getName != NULL)
            {
                name = getName();

                // Check to see it plug-in is already registered
                int pluginsWithName =  mRegisteredImplementations.count(name);
                if ( pluginsWithName < 1 )
                {
                    // Keep track of the plug-ins we actual use
                    mPlugins.push_back(libs[x]);

                    vprDEBUG(snxDBG, vprDBG_STATE_LVL)
                       << "Got plug-in '" << name << "'--registering\n"
                       << vprDEBUG_FLUSH;

                    // create the implementation
                    newPluginFunc newPlugin = (newPluginFunc)libs[x]->findSymbol( "newPlugin" );
                    ISoundImplementation* si = NULL;
                    if (newPlugin != NULL)
                    {
                        si = newPlugin();
                        if (NULL != si)
                        {
                            this->reg( name, si );
                        }
                    }
                }
                else
                {
                    //Plug in was already registered so we can unload it
                    libs[x]->unload();
                }
            }
        }
      }
      else
      {
        //Lib failed to load
        vprDEBUG(snxDBG, vprDBG_WARNING_LVL)
            << "ERROR: Plugin '" << libs[x]->getName() << "' Failed to load\n" << vprDEBUG_FLUSH;
      }
   }
}

void SoundFactory::unloadPlugins()
{
   for (unsigned int x = 0; x < mPlugins.size(); ++x)
   {
      // get the name..
      getNameFunc getName = (getNameFunc)mPlugins[x]->findSymbol( "getName" );
      std::string name;
      ISoundImplementation* impl = NULL;
      if (getName != NULL)
      {
         name = getName();
         impl = mRegisteredImplementations[name];

         // unreg it.
         this->reg( name, NULL );
      }

      // delete the memory using the delete func that comes with the library...
      if ( NULL != impl )
      {
         delete impl;
      }

      // close the library
      mPlugins[x]->unload();
   }
   mPlugins.clear();
}

void SoundFactory::reg(const std::string& apiName,
                       snx::ISoundImplementation* impl)
{
   if (impl != NULL)
   {
      vprDEBUG(snxDBG, vprDBG_CONFIG_LVL)
         << "NOTICE: Registering sound API '" << apiName << "'\n"
         << vprDEBUG_FLUSH;

      impl->setName( apiName );
      mRegisteredImplementations[apiName] = impl;
   }
   else
   {
      mRegisteredImplementations.erase( apiName );

      vprDEBUG(snxDBG, vprDBG_CONFIG_LVL)
         << "NOTICE: Unregistered sound API '" << apiName << "'\n"
         << vprDEBUG_FLUSH;
   }
}

/**
 * @input name of api to create
 * @output an implementation is returned for you to use
 * @postconditions if apiName is not known, then a stub implementation is returned
 * @semantics factory function used to create an implementation of a sound API
 */
void SoundFactory::createImplementation( const std::string& apiName,
                           snx::ISoundImplementation* &mImplementation )
{
   if (mRegisteredImplementations.count( apiName ) > 0)
   {
      mRegisteredImplementations[apiName]->clone( mImplementation );
   }

   else
   {
      mImplementation = new snx::StubSoundImplementation;
   }

   //mImplementation->setName( apiName );
}

} // end namespace
<commit_msg>Catch exceptions that Boost.Filesystem code might throw, and ensure that native paths can be used when searching for Sonix plug-ins.<commit_after>/****************** <SNX heading BEGIN do not edit this line> *****************
 *
 * sonix
 *
 * Original Authors:
 *   Kevin Meinert
 *
 * -----------------------------------------------------------------
 * File:          $RCSfile$
 * Date modified: $Date$
 * Version:       $Revision$
 * -----------------------------------------------------------------
 *
 ****************** <SNX heading END do not edit this line> ******************/

/*************** <auto-copyright.pl BEGIN do not edit this line> **************
 *
 * VR Juggler is (C) Copyright 1998-2003 by Iowa State University
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 *************** <auto-copyright.pl END do not edit this line> ***************/

#include <snx/snxConfig.h>

#include <iostream>
#include <fstream>
#include <string>

#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/operations.hpp>

#include <vpr/vpr.h>
#include <vpr/System.h>
#include <vpr/Util/FileUtils.h>
#include <vpr/DynLoad/LibraryFinder.h>

#include <snx/Util/Debug.h>
#include "snx/ISoundImplementation.h"
#include "snx/StubSoundImplementation.h" // in case lookup fails...

#include "snx/SoundFactory.h" // my header.

namespace snx
{

/**
 * Create the plugin.
 * Symbol name to look up from the shared lib is "newPlugin".
 */
typedef snx::ISoundImplementation* (*newPluginFunc)(void);

/**
 * Gets the name of the plugin.
 * Symbol name to lookup from the shared lib is "getName".
 */
typedef char* (*getNameFunc)(void);

/**
 * Get the version of sonix plugin was compiled against.
 * Symbol name to lookup from the shared lib is "getVersion".
 */
typedef char* (*getVersionFunc)(void);

vprSingletonImp(SoundFactory);

SoundFactory::SoundFactory()
{
   std::vector<std::string> search_paths;

   const std::string envvar("SNX_BASE_DIR");
   std::string dummy_result;

   if ( vpr::System::getenv(envvar, dummy_result).failure() )
   {
      vprDEBUG(snxDBG, vprDBG_WARNING_LVL)
         << clrOutBOLD(clrYELLOW, "WARNING:")
         << " SNX_BASE_DIR environment variable not set!\n" << vprDEBUG_FLUSH;
      vprDEBUG_NEXT(snxDBG, vprDBG_WARNING_LVL)
         << "Plug-in loading may fail.\n" << vprDEBUG_FLUSH;
   }

#if defined(_ABIN32)
   std::string snx_lib_dir("${SNX_BASE_DIR}/lib32/snx/plugins");
#elif defined(_ABI64)
   std::string snx_lib_dir("${SNX_BASE_DIR}/lib64/snx/plugins");
#else
   std::string snx_lib_dir("${SNX_BASE_DIR}/lib/snx/plugins");
#endif

#ifdef SNX_DEBUG
   snx_lib_dir += std::string("/dbg");
#else
   snx_lib_dir += std::string("/opt");
#endif

#if defined(VPR_OS_Win32)
   const std::string driver_ext("dll");
#elif defined(VPR_OS_Darwin)
   const std::string driver_ext("dylib");
#else
   const std::string driver_ext("so");
#endif

   search_paths.push_back(snx_lib_dir);
   search_paths.push_back( "${HOME}/.sonix/plugins" );

   for (unsigned int x = 0; x < search_paths.size(); ++x)
   {
      search_paths[x] = vpr::replaceEnvVars(search_paths[x]);
      vprDEBUG(snxDBG, vprDBG_CONFIG_LVL) << "Finding plugins in "
                                          << search_paths[x] << std::endl
                                          << vprDEBUG_FLUSH;

      try
      {
         boost::filesystem::path dirPath(search_paths[x], boost::filesystem::native);
         if (boost::filesystem::exists(dirPath))
         {
            vpr::LibraryFinder finder(search_paths[x], driver_ext);
            vpr::LibraryFinder::LibraryList libs = finder.getLibraries();
            this->loadPlugins( libs );

#ifdef SNX_DEBUG
            vprDEBUG(snxDBG, vprDBG_CONFIG_LVL) << "filelist:\n"
                                                << vprDEBUG_FLUSH;
            for ( unsigned int i = 0; i < libs.size(); ++i )
            {
               vprDEBUG(snxDBG, vprDBG_CONFIG_LVL) << "\t" << libs[i]
                                                   << std::endl
                                                   << vprDEBUG_FLUSH;
            }
#endif
         }
         else
         {
            vprDEBUG(snxDBG, vprDBG_STATE_LVL)
               << "The directory does not exist: '" << search_paths[x] << "'\n"
               << vprDEBUG_FLUSH;
         }
      }
      catch (boost::filesystem::filesystem_error& fsEx)
      {
         vprDEBUG(snxDBG, vprDBG_CRITICAL_LVL)
            << clrOutNORM(clrRED, "ERROR:")
            << " File system exception caught: " << fsEx.what() << std::endl
            << vprDEBUG_FLUSH;
      }
   }
}

void SoundFactory::errorOutput(vpr::LibraryPtr lib, const char* test)
{
   vprDEBUG(snxDBG, vprDBG_WARNING_LVL)
      << "ERROR: Plugin '" << lib->getName() << "' does not export symbol '"
      << test << "'\n" << vprDEBUG_FLUSH;
}

bool SoundFactory::isPlugin(vpr::LibraryPtr lib)
{
   if (lib->findSymbol( "newPlugin" ) == NULL)
   {
      errorOutput(lib, "newPlugin");
      return false;
   }
   if (lib->findSymbol( "getVersion" ) == NULL)
   {
      errorOutput(lib, "getVersion");
      return false;
   }
   if (lib->findSymbol( "getName" ) == NULL)
   {
      errorOutput(lib, "getName");
      return false;
   }

   // @todo give sonix an internal version number string!
   //getVersionFunc getVersion = (getVersionFunc)lib.lookup( "getVersion" );
   //if (getVersion != NULL && getVersion() != snx::version) return false;
   vprDEBUG(snxDBG, vprDBG_CONFIG_STATUS_LVL) << "Plugin '" << lib->getName()
                                              << "' is a valid Sonix plugin.\n"
                                              << vprDEBUG_FLUSH;
   return true;
}

void SoundFactory::loadPlugins( vpr::LibraryFinder::LibraryList libs )
{
   for (unsigned int x = 0; x < libs.size(); ++x)
   {
      // open the library
      vpr::ReturnStatus didLoad = libs[x]->load();

      if (didLoad == vpr::ReturnStatus::Succeed)
      {
        //If the plug-in implements the nessiasry interface
        if ( this->isPlugin(libs[x]) )
        {
            // get the name..
            getNameFunc getName = (getNameFunc)libs[x]->findSymbol( "getName" );
            std::string name;
            if (getName != NULL)
            {
                name = getName();

                // Check to see it plug-in is already registered
                int pluginsWithName =  mRegisteredImplementations.count(name);
                if ( pluginsWithName < 1 )
                {
                    // Keep track of the plug-ins we actual use
                    mPlugins.push_back(libs[x]);

                    vprDEBUG(snxDBG, vprDBG_STATE_LVL)
                       << "Got plug-in '" << name << "'--registering\n"
                       << vprDEBUG_FLUSH;

                    // create the implementation
                    newPluginFunc newPlugin = (newPluginFunc)libs[x]->findSymbol( "newPlugin" );
                    ISoundImplementation* si = NULL;
                    if (newPlugin != NULL)
                    {
                        si = newPlugin();
                        if (NULL != si)
                        {
                            this->reg( name, si );
                        }
                    }
                }
                else
                {
                    //Plug in was already registered so we can unload it
                    libs[x]->unload();
                }
            }
        }
      }
      else
      {
        //Lib failed to load
        vprDEBUG(snxDBG, vprDBG_WARNING_LVL)
            << "ERROR: Plugin '" << libs[x]->getName() << "' Failed to load\n" << vprDEBUG_FLUSH;
      }
   }
}

void SoundFactory::unloadPlugins()
{
   for (unsigned int x = 0; x < mPlugins.size(); ++x)
   {
      // get the name..
      getNameFunc getName = (getNameFunc)mPlugins[x]->findSymbol( "getName" );
      std::string name;
      ISoundImplementation* impl = NULL;
      if (getName != NULL)
      {
         name = getName();
         impl = mRegisteredImplementations[name];

         // unreg it.
         this->reg( name, NULL );
      }

      // delete the memory using the delete func that comes with the library...
      if ( NULL != impl )
      {
         delete impl;
      }

      // close the library
      mPlugins[x]->unload();
   }
   mPlugins.clear();
}

void SoundFactory::reg(const std::string& apiName,
                       snx::ISoundImplementation* impl)
{
   if (impl != NULL)
   {
      vprDEBUG(snxDBG, vprDBG_CONFIG_LVL)
         << "NOTICE: Registering sound API '" << apiName << "'\n"
         << vprDEBUG_FLUSH;

      impl->setName( apiName );
      mRegisteredImplementations[apiName] = impl;
   }
   else
   {
      mRegisteredImplementations.erase( apiName );

      vprDEBUG(snxDBG, vprDBG_CONFIG_LVL)
         << "NOTICE: Unregistered sound API '" << apiName << "'\n"
         << vprDEBUG_FLUSH;
   }
}

/**
 * @input name of api to create
 * @output an implementation is returned for you to use
 * @postconditions if apiName is not known, then a stub implementation is returned
 * @semantics factory function used to create an implementation of a sound API
 */
void SoundFactory::createImplementation( const std::string& apiName,
                           snx::ISoundImplementation* &mImplementation )
{
   if (mRegisteredImplementations.count( apiName ) > 0)
   {
      mRegisteredImplementations[apiName]->clone( mImplementation );
   }

   else
   {
      mImplementation = new snx::StubSoundImplementation;
   }

   //mImplementation->setName( apiName );
}

} // end namespace
<|endoftext|>


<commit_before>#include "menger_sponge.h"
#include "utilities.h"

#include <stack>
#include <iostream>
#include <map>
#include <cmath>

struct Quad
make_quad (struct Point a, struct Point b, struct Point c, struct Point d)
{
	struct Point A = a;
	struct Point B = b;
	struct Point C = c;
	struct Point D = d;

	A.color = random_color();
	B.color = random_color();
	C.color = random_color();
	D.color = random_color();

	struct Normal normal = compute_normal(A - B, B - C);
	A.normal = normal;
	B.normal = normal;
	C.normal = normal;
	D.normal = normal;

	struct TexCoord tc1 {{0.0, 0.0}};
	struct TexCoord tc2 {{1.0, 0.0}};
	struct TexCoord tc3 {{1.0, 1.0}};
	struct TexCoord tc4 {{0.0, 1.0}};

	A.tex_coord = tc1;
	B.tex_coord = tc2;
	C.tex_coord = tc3;
	D.tex_coord = tc4;

	struct Quad result {A, B, C, D};
	return result;
}

struct Cube
cube_starting_with (int i, int j, int k, struct Point (*cube_points)[4][4])
{
	struct Cube result {
		cube_points[i+0][j+0][k+0],
		cube_points[i+1][j+0][k+0],
		cube_points[i+1][j+0][k+1],
		cube_points[i+0][j+0][k+1],

		cube_points[i+0][j+1][k+0],
		cube_points[i+1][j+1][k+0],
		cube_points[i+1][j+1][k+1],
		cube_points[i+0][j+1][k+1],
		};

	return result;
}

struct Point
lin_interpol (struct Point a, struct Point b, GLfloat tx, GLfloat ty, GLfloat
    tz)
{
	GLfloat new_x = a.x + (b.x - a.x) * tx;
	GLfloat new_y = a.y + (b.y - a.y) * ty;
	GLfloat new_z = a.z + (b.z - a.z) * tz;

	std::cout << new_x << " " << new_y << " " <<  new_z << std::endl;

	struct Point result {new_x, new_y, new_z};
	return result;
}

std::vector<struct Quad>
create_menger_sponge(struct Cube base, unsigned int depth)
{
	std::stack<std::pair<struct Cube, unsigned int>> stack;
	std::vector<struct Quad> result;

	stack.push(std::make_pair(base, depth));
	while (!stack.empty())
	{
		std::pair<struct Cube, unsigned int> top = stack.top();
		stack.pop();

		struct Point a = top.first.points[0];
		struct Point b = top.first.points[1];
		struct Point c = top.first.points[2];
		struct Point d = top.first.points[3];
		struct Point e = top.first.points[4];
		struct Point f = top.first.points[5];
		struct Point g = top.first.points[6];
		struct Point h = top.first.points[7];

		if (top.second == 0)
		{
			result.push_back(make_quad(a, b, c, d));
			result.push_back(make_quad(e, f, g, h));
			result.push_back(make_quad(a, b, f, e));
			result.push_back(make_quad(c, d, h, g));
			result.push_back(make_quad(b, c, g, f));
			result.push_back(make_quad(a, d, h, e));
		}
		else
		{
			struct Point cube[4][4][4];
			for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++)
			for (int k = 0; k < 4; k++)
			{
				cube[i][j][k] = lin_interpol(a, g,
					(GLfloat)i/3.0,
					(GLfloat)j/3.0,
					(GLfloat)k/3.0);

			}

			// cube front face
			struct Cube cf1 = cube_starting_with(0, 0, 0, cube);
			struct Cube cf2 = cube_starting_with(1, 0, 0, cube);
			struct Cube cf3 = cube_starting_with(2, 0, 0, cube);
			struct Cube cf4 = cube_starting_with(0, 1, 0, cube);
			struct Cube cf5 = cube_starting_with(2, 1, 0, cube);
			struct Cube cf6 = cube_starting_with(0, 2, 0, cube);
			struct Cube cf7 = cube_starting_with(1, 2, 0, cube);
			struct Cube cf8 = cube_starting_with(2, 2, 0, cube);

			// cube back face
			struct Cube cb1 = cube_starting_with(0, 0, 2, cube);
			struct Cube cb2 = cube_starting_with(1, 0, 2, cube);
			struct Cube cb3 = cube_starting_with(2, 0, 2, cube);
			struct Cube cb4 = cube_starting_with(0, 1, 2, cube);
			struct Cube cb5 = cube_starting_with(2, 1, 2, cube);
			struct Cube cb6 = cube_starting_with(0, 2, 2, cube);
			struct Cube cb7 = cube_starting_with(1, 2, 2, cube);
			struct Cube cb8 = cube_starting_with(2, 2, 2, cube);

			// cube side faces
			struct Cube cs1 = cube_starting_with(2, 0, 1, cube);
			struct Cube cs2 = cube_starting_with(2, 2, 1, cube);
			struct Cube cs3 = cube_starting_with(0, 0, 1, cube);
			struct Cube cs4 = cube_starting_with(0, 2, 1, cube);

			stack.push(std::make_pair(cf1, top.second-1));
			stack.push(std::make_pair(cf2, top.second-1));
			stack.push(std::make_pair(cf3, top.second-1));
			stack.push(std::make_pair(cf4, top.second-1));
			stack.push(std::make_pair(cf5, top.second-1));
			stack.push(std::make_pair(cf6, top.second-1));
			stack.push(std::make_pair(cf7, top.second-1));
			stack.push(std::make_pair(cf8, top.second-1));
			stack.push(std::make_pair(cb1, top.second-1));
			stack.push(std::make_pair(cb2, top.second-1));
			stack.push(std::make_pair(cb3, top.second-1));
			stack.push(std::make_pair(cb4, top.second-1));
			stack.push(std::make_pair(cb5, top.second-1));
			stack.push(std::make_pair(cb6, top.second-1));
			stack.push(std::make_pair(cb7, top.second-1));
			stack.push(std::make_pair(cb8, top.second-1));
			stack.push(std::make_pair(cs1, top.second-1));
			stack.push(std::make_pair(cs2, top.second-1));
			stack.push(std::make_pair(cs3, top.second-1));
			stack.push(std::make_pair(cs4, top.second-1));
		}
	}

	return result;
}

<commit_msg>Removed slow printing<commit_after>#include "menger_sponge.h"
#include "utilities.h"

#include <stack>
#include <iostream>
#include <map>
#include <cmath>

struct Quad
make_quad (struct Point a, struct Point b, struct Point c, struct Point d)
{
	struct Point A = a;
	struct Point B = b;
	struct Point C = c;
	struct Point D = d;

	A.color = random_color();
	B.color = random_color();
	C.color = random_color();
	D.color = random_color();

	struct Normal normal = compute_normal(A - B, B - C);
	A.normal = normal;
	B.normal = normal;
	C.normal = normal;
	D.normal = normal;

	struct TexCoord tc1 {{0.0, 0.0}};
	struct TexCoord tc2 {{1.0, 0.0}};
	struct TexCoord tc3 {{1.0, 1.0}};
	struct TexCoord tc4 {{0.0, 1.0}};

	A.tex_coord = tc1;
	B.tex_coord = tc2;
	C.tex_coord = tc3;
	D.tex_coord = tc4;

	struct Quad result {A, B, C, D};
	return result;
}

struct Cube
cube_starting_with (int i, int j, int k, struct Point (*cube_points)[4][4])
{
	struct Cube result {
		cube_points[i+0][j+0][k+0],
		cube_points[i+1][j+0][k+0],
		cube_points[i+1][j+0][k+1],
		cube_points[i+0][j+0][k+1],

		cube_points[i+0][j+1][k+0],
		cube_points[i+1][j+1][k+0],
		cube_points[i+1][j+1][k+1],
		cube_points[i+0][j+1][k+1],
		};

	return result;
}

struct Point
lin_interpol (struct Point a, struct Point b, GLfloat tx, GLfloat ty, GLfloat
    tz)
{
	GLfloat new_x = a.x + (b.x - a.x) * tx;
	GLfloat new_y = a.y + (b.y - a.y) * ty;
	GLfloat new_z = a.z + (b.z - a.z) * tz;

	struct Point result {new_x, new_y, new_z};
	return result;
}

std::vector<struct Quad>
create_menger_sponge(struct Cube base, unsigned int depth)
{
	std::stack<std::pair<struct Cube, unsigned int>> stack;
	std::vector<struct Quad> result;

	stack.push(std::make_pair(base, depth));
	while (!stack.empty())
	{
		std::pair<struct Cube, unsigned int> top = stack.top();
		stack.pop();

		struct Point a = top.first.points[0];
		struct Point b = top.first.points[1];
		struct Point c = top.first.points[2];
		struct Point d = top.first.points[3];
		struct Point e = top.first.points[4];
		struct Point f = top.first.points[5];
		struct Point g = top.first.points[6];
		struct Point h = top.first.points[7];

		if (top.second == 0)
		{
			result.push_back(make_quad(a, b, c, d));
			result.push_back(make_quad(e, f, g, h));
			result.push_back(make_quad(a, b, f, e));
			result.push_back(make_quad(c, d, h, g));
			result.push_back(make_quad(b, c, g, f));
			result.push_back(make_quad(a, d, h, e));
		}
		else
		{
			struct Point cube[4][4][4];
			for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++)
			for (int k = 0; k < 4; k++)
			{
				cube[i][j][k] = lin_interpol(a, g,
					(GLfloat)i/3.0,
					(GLfloat)j/3.0,
					(GLfloat)k/3.0);
			}

			// cube front face
			struct Cube cf1 = cube_starting_with(0, 0, 0, cube);
			struct Cube cf2 = cube_starting_with(1, 0, 0, cube);
			struct Cube cf3 = cube_starting_with(2, 0, 0, cube);
			struct Cube cf4 = cube_starting_with(0, 1, 0, cube);
			struct Cube cf5 = cube_starting_with(2, 1, 0, cube);
			struct Cube cf6 = cube_starting_with(0, 2, 0, cube);
			struct Cube cf7 = cube_starting_with(1, 2, 0, cube);
			struct Cube cf8 = cube_starting_with(2, 2, 0, cube);

			// cube back face
			struct Cube cb1 = cube_starting_with(0, 0, 2, cube);
			struct Cube cb2 = cube_starting_with(1, 0, 2, cube);
			struct Cube cb3 = cube_starting_with(2, 0, 2, cube);
			struct Cube cb4 = cube_starting_with(0, 1, 2, cube);
			struct Cube cb5 = cube_starting_with(2, 1, 2, cube);
			struct Cube cb6 = cube_starting_with(0, 2, 2, cube);
			struct Cube cb7 = cube_starting_with(1, 2, 2, cube);
			struct Cube cb8 = cube_starting_with(2, 2, 2, cube);

			// cube side faces
			struct Cube cs1 = cube_starting_with(2, 0, 1, cube);
			struct Cube cs2 = cube_starting_with(2, 2, 1, cube);
			struct Cube cs3 = cube_starting_with(0, 0, 1, cube);
			struct Cube cs4 = cube_starting_with(0, 2, 1, cube);

			stack.push(std::make_pair(cf1, top.second-1));
			stack.push(std::make_pair(cf2, top.second-1));
			stack.push(std::make_pair(cf3, top.second-1));
			stack.push(std::make_pair(cf4, top.second-1));
			stack.push(std::make_pair(cf5, top.second-1));
			stack.push(std::make_pair(cf6, top.second-1));
			stack.push(std::make_pair(cf7, top.second-1));
			stack.push(std::make_pair(cf8, top.second-1));
			stack.push(std::make_pair(cb1, top.second-1));
			stack.push(std::make_pair(cb2, top.second-1));
			stack.push(std::make_pair(cb3, top.second-1));
			stack.push(std::make_pair(cb4, top.second-1));
			stack.push(std::make_pair(cb5, top.second-1));
			stack.push(std::make_pair(cb6, top.second-1));
			stack.push(std::make_pair(cb7, top.second-1));
			stack.push(std::make_pair(cb8, top.second-1));
			stack.push(std::make_pair(cs1, top.second-1));
			stack.push(std::make_pair(cs2, top.second-1));
			stack.push(std::make_pair(cs3, top.second-1));
			stack.push(std::make_pair(cs4, top.second-1));
		}
	}

	return result;
}

<|endoftext|>


<commit_before><commit_msg>:lipstick: Remove unnsessary includes in test.cc<commit_after><|endoftext|>


<commit_before><commit_msg>Define aliases for items in static_string namespace and rename sss<commit_after><|endoftext|>


<commit_before>#include "QZXingImageProvider.h"
#include <QDebug>
#include <QUrlQuery>
#include "QZXing.h"

QZXingImageProvider::QZXingImageProvider() : QQuickImageProvider(QQuickImageProvider::Image)
{
}

QImage QZXingImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    int slashIndex = id.indexOf('/');
    if (slashIndex == -1)
    {
        qWarning() << "Can't parse url" << id << ". Usage is encode?<format>/<data>";
        return QImage();
    }

    //Detect operation (ex. encode)
    QString operationName = id.left(slashIndex);
    if(operationName != "encode")
    {
        qWarning() << "Operation not supported: " << operationName;
        return QImage();
    }

    QString data;
    QZXing::EncoderFormat format = QZXing::EncoderFormat_QR_CODE;
    QZXing::EncodeErrorCorrectionLevel correctionLevel = QZXing::EncodeErrorCorrectionLevel_L;

    int customSettingsIndex = id.lastIndexOf(QRegExp("\?[cf]"));
    if(customSettingsIndex >= 0)
    {
        int startOfDataIndex = slashIndex + 1;
        data = id.mid(startOfDataIndex, customSettingsIndex - (startOfDataIndex));

        //The dummy option has been added due to a bug(?) of QUrlQuery
        // it could not recognize the first key-value pair provided
        QUrlQuery optionQuery("options?dummy=&" + id.mid(customSettingsIndex + 1));

        if (optionQuery.hasQueryItem("format")) {
            QString formatString = optionQuery.queryItemValue("format");
            if (formatString != "qrcode") {
                qWarning() << "Format not supported: " << formatString;
                return QImage();
            }
        }

        QString correctionLevelString = optionQuery.queryItemValue("corretionLevel");
        if(correctionLevelString == "H")
            correctionLevel = QZXing::EncodeErrorCorrectionLevel_H;
        else if(correctionLevelString == "Q")
            correctionLevel = QZXing::EncodeErrorCorrectionLevel_Q;
        else if(correctionLevelString == "M")
            correctionLevel = QZXing::EncodeErrorCorrectionLevel_M;
        else if(correctionLevelString == "L")
            correctionLevel = QZXing::EncodeErrorCorrectionLevel_L;
    } else
    {
        data = id.mid(slashIndex + 1);
    }

    QImage result = QZXing::encodeData(data, format, requestedSize, correctionLevel);
    *size = result.size();
    return result;
}
<commit_msg>enhance #140 with an even stricter regex expression to minimize possibility of conflict between actual data and encoding options. Fixes #139<commit_after>#include "QZXingImageProvider.h"
#include <QDebug>
#include <QUrlQuery>
#include "QZXing.h"

QZXingImageProvider::QZXingImageProvider() : QQuickImageProvider(QQuickImageProvider::Image)
{
}

QImage QZXingImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    int slashIndex = id.indexOf('/');
    if (slashIndex == -1)
    {
        qWarning() << "Can't parse url" << id << ". Usage is encode?<format>/<data>";
        return QImage();
    }

    //Detect operation (ex. encode)
    QString operationName = id.left(slashIndex);
    if(operationName != "encode")
    {
        qWarning() << "Operation not supported: " << operationName;
        return QImage();
    }

    QString data;
    QZXing::EncoderFormat format = QZXing::EncoderFormat_QR_CODE;
    QZXing::EncodeErrorCorrectionLevel correctionLevel = QZXing::EncodeErrorCorrectionLevel_L;

    int customSettingsIndex = id.lastIndexOf(QRegExp("\?(corretionLevel|format)="));
    if(customSettingsIndex >= 0)
    {
        int startOfDataIndex = slashIndex + 1;
        data = id.mid(startOfDataIndex, customSettingsIndex - (startOfDataIndex));

        //The dummy option has been added due to a bug(?) of QUrlQuery
        // it could not recognize the first key-value pair provided
        QUrlQuery optionQuery("options?dummy=&" + id.mid(customSettingsIndex + 1));

        if (optionQuery.hasQueryItem("format")) {
            QString formatString = optionQuery.queryItemValue("format");
            if (formatString != "qrcode") {
                qWarning() << "Format not supported: " << formatString;
                return QImage();
            }
        }

        QString correctionLevelString = optionQuery.queryItemValue("corretionLevel");
        if(correctionLevelString == "H")
            correctionLevel = QZXing::EncodeErrorCorrectionLevel_H;
        else if(correctionLevelString == "Q")
            correctionLevel = QZXing::EncodeErrorCorrectionLevel_Q;
        else if(correctionLevelString == "M")
            correctionLevel = QZXing::EncodeErrorCorrectionLevel_M;
        else if(correctionLevelString == "L")
            correctionLevel = QZXing::EncodeErrorCorrectionLevel_L;
    } else
    {
        data = id.mid(slashIndex + 1);
    }

    QImage result = QZXing::encodeData(data, format, requestedSize, correctionLevel);
    *size = result.size();
    return result;
}
<|endoftext|>


<commit_before>/*
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <list>
#include "RtpBroadCaster.h"
#include "Util/util.h"
#include "Network/sockutil.h"

namespace ZL {
namespace Rtsp {

std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) {
	lock_guard<recursive_mutex> lck(m_mtx);
	static uint32_t addrMin = mINI::Instance()[Config::MultiCast::kAddrMin].as<uint32_t>();
	static uint32_t addrMax = mINI::Instance()[Config::MultiCast::kAddrMax].as<uint32_t>();
	if(m_iAddr > addrMax){
		m_iAddr = addrMin;
	}
	auto iGotAddr =  m_iAddr++;
	if(m_setBadAddr.find(iGotAddr) != m_setBadAddr.end()){
		//已经分配过了
		if(iTry){
			return obtain(--iTry);
		}
		//分配完了,应该不可能到这里
		FatalL;
		return nullptr;
	}
	m_setBadAddr.emplace(iGotAddr);
	std::shared_ptr<uint32_t> ret(new uint32_t(iGotAddr),[](uint32_t *ptr){
		auto val = *ptr;
		MultiCastAddressMaker::Instance().release(val);
		delete ptr;
	});
	return ret;
}
void MultiCastAddressMaker::release(uint32_t iAddr){
	lock_guard<recursive_mutex> lck(m_mtx);
	m_setBadAddr.erase(iAddr);
}

recursive_mutex RtpBroadCaster::g_mtx;
unordered_map<string, weak_ptr<RtpBroadCaster> > RtpBroadCaster::g_mapBroadCaster;

void RtpBroadCaster::setDetachCB(void* listener, const onDetach& cb) {
	lock_guard<recursive_mutex> lck(m_mtx);
	if(cb){
		m_mapDetach.emplace(listener,cb);
	}else{
		m_mapDetach.erase(listener);
	}
}
RtpBroadCaster::~RtpBroadCaster() {
	m_pReader->setReadCB(nullptr);
	m_pReader->setDetachCB(nullptr);
	DebugL;
}
RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strApp,const string &strStream) {
	auto src = RtspMediaSource::find(strApp, strStream);
	if(!src){
		auto strErr = StrPrinter << "未找到媒体源:" << strApp << " " << strStream << endl;
		throw std::runtime_error(strErr);
	}
	m_multiAddr = MultiCastAddressMaker::Instance().obtain();
	for(auto i = 0; i < 2; i++){
		m_apUdpSock[i].reset(new Socket());
		if(!m_apUdpSock[i]->bindUdpSock(0, strLocalIp.data())){
			auto strErr = StrPrinter << "绑定UDP端口失败:" << strLocalIp << endl;
			throw std::runtime_error(strErr);
		}
		auto fd = m_apUdpSock[i]->rawFD();
		static uint32_t udpTTL = mINI::Instance()[Config::MultiCast::kUdpTTL].as<uint32_t>();
		SockUtil::setMultiTTL(fd, udpTTL);
		SockUtil::setMultiLOOP(fd, false);
		SockUtil::setMultiIF(fd, strLocalIp.data());

		struct sockaddr_in &peerAddr = m_aPeerUdpAddr[i];
		peerAddr.sin_family = AF_INET;
		peerAddr.sin_port = htons(m_apUdpSock[i]->get_local_port());
		peerAddr.sin_addr.s_addr = htonl(*m_multiAddr);
		bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
	}
	m_pReader = src->getRing()->attach();
	m_pReader->setReadCB([this](const RtpPacket::Ptr &pkt){
		int i = (pkt->interleaved/2)%2;
		auto &pSock = m_apUdpSock[i];
		auto &peerAddr = m_aPeerUdpAddr[i];
		pSock->sendTo((char *) pkt->payload + 4, pkt->length - 4,(struct sockaddr *)(&peerAddr));
	});
	m_pReader->setDetachCB([this](){
		unordered_map<void * , onDetach > m_mapDetach_copy;
		{
			lock_guard<recursive_mutex> lck(m_mtx);
			m_mapDetach_copy.swap(m_mapDetach);
		}
		for(auto &pr : m_mapDetach_copy){
			pr.second();
		}
	});
	DebugL << MultiCastAddressMaker::toString(*m_multiAddr) << " "
			<< m_apUdpSock[0]->get_local_port() << " "
			<< m_apUdpSock[1]->get_local_port() << " "
			<< strApp << " " << strStream;
}
uint16_t RtpBroadCaster::getPort(int iTrackId){
	int i = iTrackId%2;
	return m_apUdpSock[i]->get_local_port();
}
string RtpBroadCaster::getIP(){
	return inet_ntoa(m_aPeerUdpAddr[0].sin_addr);
}
RtpBroadCaster::Ptr RtpBroadCaster::make(const string &strLocalIp,const string &strApp,const string &strStream){
	try{
		auto ret = Ptr(new RtpBroadCaster(strLocalIp,strApp,strStream));
		lock_guard<recursive_mutex> lck(g_mtx);
		string strKey = StrPrinter << strLocalIp << " " << strApp << " " << strStream << endl;
		weak_ptr<RtpBroadCaster> weakPtr = ret;
		g_mapBroadCaster.emplace(strKey,weakPtr);
		return ret;
	}catch (std::exception &ex) {
		WarnL << ex.what();
		return nullptr;
	}
}

RtpBroadCaster::Ptr RtpBroadCaster::get(const string &strLocalIp,const string& strApp, const string& strStream) {
	string strKey = StrPrinter << strLocalIp << " " << strApp << " " << strStream << endl;
	lock_guard<recursive_mutex> lck(g_mtx);
	auto it = g_mapBroadCaster.find(strKey);
	if (it == g_mapBroadCaster.end()) {
		return make(strLocalIp,strApp, strStream);
	}
	auto ret = it->second.lock();
	if (!ret) {
		g_mapBroadCaster.erase(it);
		return make(strLocalIp,strApp, strStream);
	}
	return ret;
}

} /* namespace Rtsp */
} /* namespace ZL */

<commit_msg>修复windows下编译不过的bug<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <list>
#include <type_traits>
#include "RtpBroadCaster.h"
#include "Util/util.h"
#include "Network/sockutil.h"
using namespace std;

namespace ZL {
namespace Rtsp {

std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) {
	lock_guard<recursive_mutex> lck(m_mtx);
	static uint32_t addrMin = mINI::Instance()[Config::MultiCast::kAddrMin].as<uint32_t>();
	static uint32_t addrMax = mINI::Instance()[Config::MultiCast::kAddrMax].as<uint32_t>();
	if(m_iAddr > addrMax){
		m_iAddr = addrMin;
	}
	auto iGotAddr =  m_iAddr++;
	if(m_setBadAddr.find(iGotAddr) != m_setBadAddr.end()){
		//已经分配过了
		if(iTry){
			return obtain(--iTry);
		}
		//分配完了,应该不可能到这里
		FatalL;
		return nullptr;
	}
	m_setBadAddr.emplace(iGotAddr);
	std::shared_ptr<uint32_t> ret(new uint32_t(iGotAddr),[](uint32_t *ptr){
		auto val = *ptr;
		MultiCastAddressMaker::Instance().release(val);
		delete ptr;
	});
	return ret;
}
void MultiCastAddressMaker::release(uint32_t iAddr){
	lock_guard<recursive_mutex> lck(m_mtx);
	m_setBadAddr.erase(iAddr);
}

recursive_mutex RtpBroadCaster::g_mtx;
unordered_map<string, weak_ptr<RtpBroadCaster> > RtpBroadCaster::g_mapBroadCaster;

void RtpBroadCaster::setDetachCB(void* listener, const onDetach& cb) {
	lock_guard<recursive_mutex> lck(m_mtx);
	if(cb){
		m_mapDetach.emplace(listener,cb);
	}else{
		m_mapDetach.erase(listener);
	}
}
RtpBroadCaster::~RtpBroadCaster() {
	m_pReader->setReadCB(nullptr);
	m_pReader->setDetachCB(nullptr);
	DebugL;
}
RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strApp,const string &strStream) {
	auto src = RtspMediaSource::find(strApp, strStream);
	if(!src){
		auto strErr = StrPrinter << "未找到媒体源:" << strApp << " " << strStream << endl;
		throw std::runtime_error(strErr);
	}
	m_multiAddr = MultiCastAddressMaker::Instance().obtain();
	for(auto i = 0; i < 2; i++){
		m_apUdpSock[i].reset(new Socket());
		if(!m_apUdpSock[i]->bindUdpSock(0, strLocalIp.data())){
			auto strErr = StrPrinter << "绑定UDP端口失败:" << strLocalIp << endl;
			throw std::runtime_error(strErr);
		}
		auto fd = m_apUdpSock[i]->rawFD();
		static uint32_t udpTTL = mINI::Instance()[Config::MultiCast::kUdpTTL].as<uint32_t>();
		SockUtil::setMultiTTL(fd, udpTTL);
		SockUtil::setMultiLOOP(fd, false);
		SockUtil::setMultiIF(fd, strLocalIp.data());

		struct sockaddr_in &peerAddr = m_aPeerUdpAddr[i];
		peerAddr.sin_family = AF_INET;
		peerAddr.sin_port = htons(m_apUdpSock[i]->get_local_port());
		peerAddr.sin_addr.s_addr = htonl(*m_multiAddr);
		bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
	}
	m_pReader = src->getRing()->attach();
	m_pReader->setReadCB([this](const RtpPacket::Ptr &pkt){
		int i = (pkt->interleaved/2)%2;
		auto &pSock = m_apUdpSock[i];
		auto &peerAddr = m_aPeerUdpAddr[i];
		pSock->sendTo((char *) pkt->payload + 4, pkt->length - 4,(struct sockaddr *)(&peerAddr));
	});
	m_pReader->setDetachCB([this](){
		unordered_map<void * , onDetach > m_mapDetach_copy;
		{
			lock_guard<recursive_mutex> lck(m_mtx);
			m_mapDetach_copy = std::move(m_mapDetach);
		}
		for(auto &pr : m_mapDetach_copy){
			pr.second();
		}
	});
	DebugL << MultiCastAddressMaker::toString(*m_multiAddr) << " "
			<< m_apUdpSock[0]->get_local_port() << " "
			<< m_apUdpSock[1]->get_local_port() << " "
			<< strApp << " " << strStream;
}
uint16_t RtpBroadCaster::getPort(int iTrackId){
	int i = iTrackId%2;
	return m_apUdpSock[i]->get_local_port();
}
string RtpBroadCaster::getIP(){
	return inet_ntoa(m_aPeerUdpAddr[0].sin_addr);
}
RtpBroadCaster::Ptr RtpBroadCaster::make(const string &strLocalIp,const string &strApp,const string &strStream){
	try{
		auto ret = Ptr(new RtpBroadCaster(strLocalIp,strApp,strStream));
		lock_guard<recursive_mutex> lck(g_mtx);
		string strKey = StrPrinter << strLocalIp << " " << strApp << " " << strStream << endl;
		weak_ptr<RtpBroadCaster> weakPtr = ret;
		g_mapBroadCaster.emplace(strKey,weakPtr);
		return ret;
	}catch (std::exception &ex) {
		WarnL << ex.what();
		return nullptr;
	}
}

RtpBroadCaster::Ptr RtpBroadCaster::get(const string &strLocalIp,const string& strApp, const string& strStream) {
	string strKey = StrPrinter << strLocalIp << " " << strApp << " " << strStream << endl;
	lock_guard<recursive_mutex> lck(g_mtx);
	auto it = g_mapBroadCaster.find(strKey);
	if (it == g_mapBroadCaster.end()) {
		return make(strLocalIp,strApp, strStream);
	}
	auto ret = it->second.lock();
	if (!ret) {
		g_mapBroadCaster.erase(it);
		return make(strLocalIp,strApp, strStream);
	}
	return ret;
}

} /* namespace Rtsp */
} /* namespace ZL */

<|endoftext|>


<commit_before>#include <pxp-agent/external_module.hpp>
#include <pxp-agent/module_type.hpp>
#include <pxp-agent/action_output.hpp>

#include <leatherman/execution/execution.hpp>

#include <leatherman/file_util/file.hpp>

#include <leatherman/locale/locale.hpp>

#define LEATHERMAN_LOGGING_NAMESPACE "puppetlabs.pxp_agent.external_module"
#include <leatherman/logging/logging.hpp>

#include <cpp-pcp-client/util/thread.hpp>   // this_thread::sleep_for
#include <cpp-pcp-client/util/chrono.hpp>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

#include <atomic>
#include <memory>   // std::shared_ptr
#include <utility>  // std::move

// TODO(ale): disable assert() once we're confident with the code...
// To disable assert()
// #define NDEBUG
#include <cassert>

namespace PXPAgent {

static const std::string METADATA_SCHEMA_NAME { "external_module_metadata" };
static const std::string ACTION_SCHEMA_NAME { "action_metadata" };

static const std::string METADATA_CONFIGURATION_ENTRY { "configuration" };
static const std::string METADATA_ACTIONS_ENTRY { "actions" };

static const int EXTERNAL_MODULE_FILE_ERROR_EC { 5 };

namespace fs = boost::filesystem;
namespace lth_exec = leatherman::execution;
namespace lth_file = leatherman::file_util;
namespace lth_jc   = leatherman::json_container;
namespace lth_loc  = leatherman::locale;
namespace pcp_util = PCPClient::Util;

//
// Free functions
//

// Provides the module metadata validator
PCPClient::Validator getMetadataValidator()
{
    // Metadata schema
    PCPClient::Schema metadata_schema { METADATA_SCHEMA_NAME,
                                          PCPClient::ContentType::Json };
    using T_C = PCPClient::TypeConstraint;
    metadata_schema.addConstraint("description", T_C::String, true);
    metadata_schema.addConstraint(METADATA_CONFIGURATION_ENTRY, T_C::Object, false);
    metadata_schema.addConstraint(METADATA_ACTIONS_ENTRY, T_C::Array, true);

    // 'actions' is an array of actions; define the action sub_schema
    PCPClient::Schema action_schema { ACTION_SCHEMA_NAME,
                                      PCPClient::ContentType::Json };
    action_schema.addConstraint("description", T_C::String, false);
    action_schema.addConstraint("name", T_C::String, true);
    action_schema.addConstraint("input", T_C::Object, true);
    action_schema.addConstraint("results", T_C::Object, true);

    metadata_schema.addConstraint(METADATA_ACTIONS_ENTRY, action_schema, false);

    PCPClient::Validator validator {};
    validator.registerSchema(metadata_schema);
    return validator;
}

//
// Public interface
//

ExternalModule::ExternalModule(const std::string& path,
                               const lth_jc::JsonContainer& config,
                               const std::string& spool_dir)
        : path_ { path },
          config_ { config },
          storage_ { spool_dir }
{
    fs::path module_path { path };
    module_name = module_path.stem().string();
    auto metadata = getModuleMetadata();

    try {
        if (metadata.includes(METADATA_CONFIGURATION_ENTRY)) {
            registerConfiguration(
                metadata.get<lth_jc::JsonContainer>(METADATA_CONFIGURATION_ENTRY));
        } else {
            LOG_DEBUG("Found no configuration schema for module '{1}'", module_name);
        }

        registerActions(metadata);
    } catch (lth_jc::data_error& e) {
        LOG_ERROR("Failed to retrieve metadata of module {1}: {2}",
                  module_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid metadata of module {1}", module_name) };
    }
}

ExternalModule::ExternalModule(const std::string& path,
                               const std::string& spool_dir)
        : path_ { path },
          config_ { "{}" },
          storage_ { spool_dir }
{
    fs::path module_path { path };
    module_name = module_path.stem().string();
    auto metadata = getModuleMetadata();

    try {
       registerActions(metadata);
    } catch (lth_jc::data_error& e) {
        LOG_ERROR("Failed to retrieve metadata of module {1}: {2}",
                  module_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid metadata of module {1}", module_name) };
    }
}

void ExternalModule::validateConfiguration()
{
    if (config_validator_.includesSchema(module_name)) {
        config_validator_.validate(config_, module_name);
    } else {
        LOG_DEBUG("The '{1}' configuration will not be validated; no JSON "
                  "schema is available", module_name);
    }
}

//
// Static class members
//

const int ExternalModule::OUTPUT_DELAY_MS { 100 };

void ExternalModule::processOutputAndUpdateMetadata(ActionResponse& response)
{
    if (response.output.std_out.empty()) {
        LOG_TRACE("Obtained no results on stdout for the {1}",
                  response.prettyRequestLabel());
    } else {
        LOG_TRACE("Results on stdout for the {1}: {2}",
                  response.prettyRequestLabel(), response.output.std_out);
    }

    if (response.output.exitcode != EXIT_SUCCESS) {
        LOG_TRACE("Execution failure (exit code {1}) for the {2}{3}",
                  response.output.exitcode, response.prettyRequestLabel(),
                  (response.output.std_err.empty()
                        ? ""
                        : "; stderr:\n" + response.output.std_err));
    } else if (!response.output.std_err.empty()) {
        LOG_TRACE("Output on stderr for the {1}:\n{2}",
                  response.prettyRequestLabel(), response.output.std_err);
    }

    try {
        // Ensure output format is valid JSON by instantiating
        // JsonContainer (NB: its ctor does not accept empty strings)
        lth_jc::JsonContainer results {
            (response.output.std_out.empty() ? "null" : response.output.std_out) };
        response.setValidResultsAndEnd(std::move(results));
    } catch (lth_jc::data_parse_error& e) {
        LOG_DEBUG("Obtained invalid JSON on stdout for the {1}; (validation "
                  "error: {2}); stdout:\n{3}",
                  response.prettyRequestLabel(), e.what(), response.output.std_out);
        std::string execution_error {
            lth_loc::format("The task executed for the {1} returned invalid "
                            "JSON on stdout - stderr:{2}",
                            response.prettyRequestLabel(),
                            (response.output.std_err.empty()
                                ? lth_loc::translate(" (empty)")
                                : "\n" + response.output.std_err)) };
        response.setBadResultsAndEnd(execution_error);
    }
}

//
// Private interface
//

// Metadata validator (static member)
const PCPClient::Validator ExternalModule::metadata_validator_ {
        getMetadataValidator() };

// Retrieve and validate the module's metadata
const lth_jc::JsonContainer ExternalModule::getModuleMetadata()
{
    auto exec =
#ifdef _WIN32
        lth_exec::execute("cmd.exe", { "/c", path_, "metadata" },
#else
        lth_exec::execute(path_, { "metadata" },
#endif
            0, {lth_exec::execution_options::merge_environment,
                lth_exec::execution_options::inherit_locale});

    if (!exec.error.empty()) {
        LOG_ERROR("Failed to load the external module metadata from {1}: {2}",
                  path_, exec.error);
        throw Module::LoadingError {
            lth_loc::translate("failed to load external module metadata") };
    }

    lth_jc::JsonContainer metadata;

    try {
        metadata = lth_jc::JsonContainer { exec.output };
        LOG_DEBUG("External module {1}: metadata is valid JSON", module_name);
    } catch (lth_jc::data_error& e) {
        throw Module::LoadingError {
            lth_loc::format("metadata is not in a valid JSON format: {1}", e.what()) };
    }

    try {
        metadata_validator_.validate(metadata, METADATA_SCHEMA_NAME);
        LOG_DEBUG("External module {1}: metadata validation OK", module_name);
    } catch (PCPClient::validation_error& e) {
        throw Module::LoadingError {
            lth_loc::format("metadata validation failure: {1}", e.what()) };
    }

    return metadata;
}

void ExternalModule::registerConfiguration(const lth_jc::JsonContainer& config_metadata)
{
    try {
        PCPClient::Schema configuration_schema { module_name, config_metadata };
        LOG_DEBUG("Registering module configuration schema for '{1}'", module_name);
        config_validator_.registerSchema(configuration_schema);
    } catch (PCPClient::schema_error& e) {
        LOG_ERROR("Failed to parse the configuration schema of module '{1}': {2}",
                  module_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid configuration schema of module {1}", module_name) };
    }
}

void ExternalModule::registerActions(const lth_jc::JsonContainer& metadata)
{
    for (auto& action
            : metadata.get<std::vector<lth_jc::JsonContainer>>(METADATA_ACTIONS_ENTRY))
        registerAction(action);
}

// Register the specified action after ensuring that the input and
// output schemas are valid JSON (i.e. we can instantiate Schema).
void ExternalModule::registerAction(const lth_jc::JsonContainer& action)
{
    // NOTE(ale): name, input, and output are required action entries
    auto action_name = action.get<std::string>("name");
    LOG_DEBUG("Validating action '{1} {2}'", module_name, action_name);

    try {
        auto input_schema_json = action.get<lth_jc::JsonContainer>("input");
        PCPClient::Schema input_schema { action_name, input_schema_json };

        auto results_schema_json = action.get<lth_jc::JsonContainer>("results");
        PCPClient::Schema results_schema { action_name, results_schema_json };

        // Metadata schemas are valid JSON; store metadata
        LOG_DEBUG("Action '{1} {2}' has been validated", module_name, action_name);
        actions.push_back(action_name);
        input_validator_.registerSchema(input_schema);
        results_validator_.registerSchema(results_schema);
    } catch (PCPClient::schema_error& e) {
        LOG_ERROR("Failed to parse metadata schemas of action '{1} {2}': {3}",
                  module_name, action_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid schemas of '{1} {2}'", module_name, action_name) };
    } catch (lth_jc::data_error& e) {
        LOG_ERROR("Failed to retrieve metadata schemas of action '{1} {2}': {3}",
                  module_name, action_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid metadata of '{1} {2}'", module_name, action_name) };
    }
}

std::string ExternalModule::getActionArguments(const ActionRequest& request)
{
    lth_jc::JsonContainer action_args {};
    action_args.set<lth_jc::JsonContainer>("input", request.params());

    if (!config_.empty())
        action_args.set<lth_jc::JsonContainer>("configuration", config_);

    if (request.type() == RequestType::NonBlocking) {
        fs::path r_d_p { request.resultsDir() };
        lth_jc::JsonContainer output_files {};
        output_files.set<std::string>("stdout", (r_d_p / "stdout").string());
        output_files.set<std::string>("stderr", (r_d_p / "stderr").string());
        output_files.set<std::string>("exitcode", (r_d_p / "exitcode").string());
        action_args.set<lth_jc::JsonContainer>("output_files", output_files);
    }

    return action_args.toString();
}

ActionResponse ExternalModule::callBlockingAction(const ActionRequest& request)
{
    ActionResponse response { ModuleType::External, request };
    auto action_name = request.action();
    auto action_args = getActionArguments(request);

    LOG_INFO("Executing the {1}", request.prettyLabel());
    LOG_TRACE("Input for the {1}: {2}", request.prettyLabel(), action_args);

    auto exec = lth_exec::execute(
#ifdef _WIN32
        "cmd.exe", { "/c", path_, action_name },
#else
        path_, { action_name },
#endif
        action_args,                           // args
        std::map<std::string, std::string>(),  // environment
        0,                                     // timeout
        { lth_exec::execution_options::merge_environment,
          lth_exec::execution_options::inherit_locale });  // options

    response.output = ActionOutput { exec.exit_code, exec.output, exec.error };
    ExternalModule::processOutputAndUpdateMetadata(response);
    return response;
}

ActionResponse ExternalModule::callNonBlockingAction(const ActionRequest& request)
{
    ActionResponse response { ModuleType::External, request };
    auto action_name = request.action();
    auto input_txt = getActionArguments(request);
    fs::path results_dir_path { request.resultsDir() };

    LOG_INFO("Starting a task for the {1}; stdout and stderr will be stored in {2}",
             request.prettyLabel(), request.resultsDir());
    LOG_TRACE("Input for the {1}: {2}", request.prettyLabel(), input_txt);

    // NOTE(ale,mruzicka): to avoid terminating the entire process
    // tree when the pxp-agent service stops, we use the
    // `create_detached_process` execution option which ensures
    // the child process is executed in a new process contract
    // on Solaris and a new process group on Windows

    auto exec = lth_exec::execute(
#ifdef _WIN32
        "cmd.exe", { "/c", path_, action_name },
#else
        path_, { action_name },
#endif
        input_txt,  // input arguments, passed via stdin
        std::map<std::string, std::string>(),  // environment
        [results_dir_path](size_t pid) {
            auto pid_file = (results_dir_path / "pid").string();
            lth_file::atomic_write_to_file(std::to_string(pid) + "\n", pid_file);
        },          // pid callback
        0,          // timeout
        { lth_exec::execution_options::create_detached_process,
          lth_exec::execution_options::merge_environment,
          lth_exec::execution_options::inherit_locale });  // options

    LOG_INFO("The task for the {1} has completed", request.prettyLabel());

    if (exec.exit_code == EXTERNAL_MODULE_FILE_ERROR_EC) {
        // This is unexpected. The output of the task will not be
        // available for future transaction status requests; we cannot
        // provide a reliable ActionResponse.
        std::string empty_label { lth_loc::translate("(empty)") };
        LOG_WARNING("The task process failed to write output on file for the {1}; "
                    "stdout: {2}; stderr: {3}",
                    request.prettyLabel(),
                    (exec.output.empty() ? empty_label : exec.output),
                    (exec.error.empty() ? empty_label : exec.error));
        throw Module::ProcessingError {
            lth_loc::translate("failed to write output on file") };
    }

    // Wait a bit to relax the requirement for the exitcode file being
    // written before the output ones, when the process completes
    LOG_TRACE("Waiting {1} ms before retrieving the output of {2}",
              OUTPUT_DELAY_MS, request.prettyLabel());
    pcp_util::this_thread::sleep_for(
        pcp_util::chrono::milliseconds(OUTPUT_DELAY_MS));

    // Stdout / stderr output should be on file; read it
    response.output = storage_.getOutput(request.transactionId(), exec.exit_code);
    ExternalModule::processOutputAndUpdateMetadata(response);
    return response;
}

ActionResponse ExternalModule::callAction(const ActionRequest& request)
{
    if (request.type() == RequestType::Blocking) {
        return callBlockingAction(request);
    } else {
        // Guranteed by Configuration
        assert(!request.resultsDir().empty());
        return callNonBlockingAction(request);
    }
}

}  // namespace PXPAgent
<commit_msg>(PCP-704) Use fork() to prevent deadlocks<commit_after>#include <pxp-agent/external_module.hpp>
#include <pxp-agent/module_type.hpp>
#include <pxp-agent/action_output.hpp>

#include <leatherman/execution/execution.hpp>

#include <leatherman/file_util/file.hpp>

#include <leatherman/locale/locale.hpp>

#define LEATHERMAN_LOGGING_NAMESPACE "puppetlabs.pxp_agent.external_module"
#include <leatherman/logging/logging.hpp>

#include <cpp-pcp-client/util/thread.hpp>   // this_thread::sleep_for
#include <cpp-pcp-client/util/chrono.hpp>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

#include <atomic>
#include <memory>   // std::shared_ptr
#include <utility>  // std::move

// TODO(ale): disable assert() once we're confident with the code...
// To disable assert()
// #define NDEBUG
#include <cassert>

namespace PXPAgent {

static const std::string METADATA_SCHEMA_NAME { "external_module_metadata" };
static const std::string ACTION_SCHEMA_NAME { "action_metadata" };

static const std::string METADATA_CONFIGURATION_ENTRY { "configuration" };
static const std::string METADATA_ACTIONS_ENTRY { "actions" };

static const int EXTERNAL_MODULE_FILE_ERROR_EC { 5 };

namespace fs = boost::filesystem;
namespace lth_exec = leatherman::execution;
namespace lth_file = leatherman::file_util;
namespace lth_jc   = leatherman::json_container;
namespace lth_loc  = leatherman::locale;
namespace pcp_util = PCPClient::Util;

//
// Free functions
//

// Provides the module metadata validator
PCPClient::Validator getMetadataValidator()
{
    // Metadata schema
    PCPClient::Schema metadata_schema { METADATA_SCHEMA_NAME,
                                          PCPClient::ContentType::Json };
    using T_C = PCPClient::TypeConstraint;
    metadata_schema.addConstraint("description", T_C::String, true);
    metadata_schema.addConstraint(METADATA_CONFIGURATION_ENTRY, T_C::Object, false);
    metadata_schema.addConstraint(METADATA_ACTIONS_ENTRY, T_C::Array, true);

    // 'actions' is an array of actions; define the action sub_schema
    PCPClient::Schema action_schema { ACTION_SCHEMA_NAME,
                                      PCPClient::ContentType::Json };
    action_schema.addConstraint("description", T_C::String, false);
    action_schema.addConstraint("name", T_C::String, true);
    action_schema.addConstraint("input", T_C::Object, true);
    action_schema.addConstraint("results", T_C::Object, true);

    metadata_schema.addConstraint(METADATA_ACTIONS_ENTRY, action_schema, false);

    PCPClient::Validator validator {};
    validator.registerSchema(metadata_schema);
    return validator;
}

//
// Public interface
//

ExternalModule::ExternalModule(const std::string& path,
                               const lth_jc::JsonContainer& config,
                               const std::string& spool_dir)
        : path_ { path },
          config_ { config },
          storage_ { spool_dir }
{
    fs::path module_path { path };
    module_name = module_path.stem().string();
    auto metadata = getModuleMetadata();

    try {
        if (metadata.includes(METADATA_CONFIGURATION_ENTRY)) {
            registerConfiguration(
                metadata.get<lth_jc::JsonContainer>(METADATA_CONFIGURATION_ENTRY));
        } else {
            LOG_DEBUG("Found no configuration schema for module '{1}'", module_name);
        }

        registerActions(metadata);
    } catch (lth_jc::data_error& e) {
        LOG_ERROR("Failed to retrieve metadata of module {1}: {2}",
                  module_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid metadata of module {1}", module_name) };
    }
}

ExternalModule::ExternalModule(const std::string& path,
                               const std::string& spool_dir)
        : path_ { path },
          config_ { "{}" },
          storage_ { spool_dir }
{
    fs::path module_path { path };
    module_name = module_path.stem().string();
    auto metadata = getModuleMetadata();

    try {
       registerActions(metadata);
    } catch (lth_jc::data_error& e) {
        LOG_ERROR("Failed to retrieve metadata of module {1}: {2}",
                  module_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid metadata of module {1}", module_name) };
    }
}

void ExternalModule::validateConfiguration()
{
    if (config_validator_.includesSchema(module_name)) {
        config_validator_.validate(config_, module_name);
    } else {
        LOG_DEBUG("The '{1}' configuration will not be validated; no JSON "
                  "schema is available", module_name);
    }
}

//
// Static class members
//

const int ExternalModule::OUTPUT_DELAY_MS { 100 };

void ExternalModule::processOutputAndUpdateMetadata(ActionResponse& response)
{
    if (response.output.std_out.empty()) {
        LOG_TRACE("Obtained no results on stdout for the {1}",
                  response.prettyRequestLabel());
    } else {
        LOG_TRACE("Results on stdout for the {1}: {2}",
                  response.prettyRequestLabel(), response.output.std_out);
    }

    if (response.output.exitcode != EXIT_SUCCESS) {
        LOG_TRACE("Execution failure (exit code {1}) for the {2}{3}",
                  response.output.exitcode, response.prettyRequestLabel(),
                  (response.output.std_err.empty()
                        ? ""
                        : "; stderr:\n" + response.output.std_err));
    } else if (!response.output.std_err.empty()) {
        LOG_TRACE("Output on stderr for the {1}:\n{2}",
                  response.prettyRequestLabel(), response.output.std_err);
    }

    try {
        // Ensure output format is valid JSON by instantiating
        // JsonContainer (NB: its ctor does not accept empty strings)
        lth_jc::JsonContainer results {
            (response.output.std_out.empty() ? "null" : response.output.std_out) };
        response.setValidResultsAndEnd(std::move(results));
    } catch (lth_jc::data_parse_error& e) {
        LOG_DEBUG("Obtained invalid JSON on stdout for the {1}; (validation "
                  "error: {2}); stdout:\n{3}",
                  response.prettyRequestLabel(), e.what(), response.output.std_out);
        std::string execution_error {
            lth_loc::format("The task executed for the {1} returned invalid "
                            "JSON on stdout - stderr:{2}",
                            response.prettyRequestLabel(),
                            (response.output.std_err.empty()
                                ? lth_loc::translate(" (empty)")
                                : "\n" + response.output.std_err)) };
        response.setBadResultsAndEnd(execution_error);
    }
}

//
// Private interface
//

// Metadata validator (static member)
const PCPClient::Validator ExternalModule::metadata_validator_ {
        getMetadataValidator() };

// Retrieve and validate the module's metadata
const lth_jc::JsonContainer ExternalModule::getModuleMetadata()
{
    auto exec =
#ifdef _WIN32
        lth_exec::execute("cmd.exe", { "/c", path_, "metadata" },
#else
        lth_exec::execute(path_, { "metadata" },
#endif
            0, {lth_exec::execution_options::thread_safe,
                lth_exec::execution_options::merge_environment,
                lth_exec::execution_options::inherit_locale});

    if (!exec.error.empty()) {
        LOG_ERROR("Failed to load the external module metadata from {1}: {2}",
                  path_, exec.error);
        throw Module::LoadingError {
            lth_loc::translate("failed to load external module metadata") };
    }

    lth_jc::JsonContainer metadata;

    try {
        metadata = lth_jc::JsonContainer { exec.output };
        LOG_DEBUG("External module {1}: metadata is valid JSON", module_name);
    } catch (lth_jc::data_error& e) {
        throw Module::LoadingError {
            lth_loc::format("metadata is not in a valid JSON format: {1}", e.what()) };
    }

    try {
        metadata_validator_.validate(metadata, METADATA_SCHEMA_NAME);
        LOG_DEBUG("External module {1}: metadata validation OK", module_name);
    } catch (PCPClient::validation_error& e) {
        throw Module::LoadingError {
            lth_loc::format("metadata validation failure: {1}", e.what()) };
    }

    return metadata;
}

void ExternalModule::registerConfiguration(const lth_jc::JsonContainer& config_metadata)
{
    try {
        PCPClient::Schema configuration_schema { module_name, config_metadata };
        LOG_DEBUG("Registering module configuration schema for '{1}'", module_name);
        config_validator_.registerSchema(configuration_schema);
    } catch (PCPClient::schema_error& e) {
        LOG_ERROR("Failed to parse the configuration schema of module '{1}': {2}",
                  module_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid configuration schema of module {1}", module_name) };
    }
}

void ExternalModule::registerActions(const lth_jc::JsonContainer& metadata)
{
    for (auto& action
            : metadata.get<std::vector<lth_jc::JsonContainer>>(METADATA_ACTIONS_ENTRY))
        registerAction(action);
}

// Register the specified action after ensuring that the input and
// output schemas are valid JSON (i.e. we can instantiate Schema).
void ExternalModule::registerAction(const lth_jc::JsonContainer& action)
{
    // NOTE(ale): name, input, and output are required action entries
    auto action_name = action.get<std::string>("name");
    LOG_DEBUG("Validating action '{1} {2}'", module_name, action_name);

    try {
        auto input_schema_json = action.get<lth_jc::JsonContainer>("input");
        PCPClient::Schema input_schema { action_name, input_schema_json };

        auto results_schema_json = action.get<lth_jc::JsonContainer>("results");
        PCPClient::Schema results_schema { action_name, results_schema_json };

        // Metadata schemas are valid JSON; store metadata
        LOG_DEBUG("Action '{1} {2}' has been validated", module_name, action_name);
        actions.push_back(action_name);
        input_validator_.registerSchema(input_schema);
        results_validator_.registerSchema(results_schema);
    } catch (PCPClient::schema_error& e) {
        LOG_ERROR("Failed to parse metadata schemas of action '{1} {2}': {3}",
                  module_name, action_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid schemas of '{1} {2}'", module_name, action_name) };
    } catch (lth_jc::data_error& e) {
        LOG_ERROR("Failed to retrieve metadata schemas of action '{1} {2}': {3}",
                  module_name, action_name, e.what());
        throw Module::LoadingError {
            lth_loc::format("invalid metadata of '{1} {2}'", module_name, action_name) };
    }
}

std::string ExternalModule::getActionArguments(const ActionRequest& request)
{
    lth_jc::JsonContainer action_args {};
    action_args.set<lth_jc::JsonContainer>("input", request.params());

    if (!config_.empty())
        action_args.set<lth_jc::JsonContainer>("configuration", config_);

    if (request.type() == RequestType::NonBlocking) {
        fs::path r_d_p { request.resultsDir() };
        lth_jc::JsonContainer output_files {};
        output_files.set<std::string>("stdout", (r_d_p / "stdout").string());
        output_files.set<std::string>("stderr", (r_d_p / "stderr").string());
        output_files.set<std::string>("exitcode", (r_d_p / "exitcode").string());
        action_args.set<lth_jc::JsonContainer>("output_files", output_files);
    }

    return action_args.toString();
}

ActionResponse ExternalModule::callBlockingAction(const ActionRequest& request)
{
    ActionResponse response { ModuleType::External, request };
    auto action_name = request.action();
    auto action_args = getActionArguments(request);

    LOG_INFO("Executing the {1}", request.prettyLabel());
    LOG_TRACE("Input for the {1}: {2}", request.prettyLabel(), action_args);

    auto exec = lth_exec::execute(
#ifdef _WIN32
        "cmd.exe", { "/c", path_, action_name },
#else
        path_, { action_name },
#endif
        action_args,                           // args
        std::map<std::string, std::string>(),  // environment
        0,                                     // timeout
        { lth_exec::execution_options::thread_safe,
          lth_exec::execution_options::merge_environment,
          lth_exec::execution_options::inherit_locale });  // options

    response.output = ActionOutput { exec.exit_code, exec.output, exec.error };
    ExternalModule::processOutputAndUpdateMetadata(response);
    return response;
}

ActionResponse ExternalModule::callNonBlockingAction(const ActionRequest& request)
{
    ActionResponse response { ModuleType::External, request };
    auto action_name = request.action();
    auto input_txt = getActionArguments(request);
    fs::path results_dir_path { request.resultsDir() };

    LOG_INFO("Starting a task for the {1}; stdout and stderr will be stored in {2}",
             request.prettyLabel(), request.resultsDir());
    LOG_TRACE("Input for the {1}: {2}", request.prettyLabel(), input_txt);

    // NOTE(ale,mruzicka): to avoid terminating the entire process
    // tree when the pxp-agent service stops, we use the
    // `create_detached_process` execution option which ensures
    // the child process is executed in a new process contract
    // on Solaris and a new process group on Windows

    auto exec = lth_exec::execute(
#ifdef _WIN32
        "cmd.exe", { "/c", path_, action_name },
#else
        path_, { action_name },
#endif
        input_txt,  // input arguments, passed via stdin
        std::map<std::string, std::string>(),  // environment
        [results_dir_path](size_t pid) {
            auto pid_file = (results_dir_path / "pid").string();
            lth_file::atomic_write_to_file(std::to_string(pid) + "\n", pid_file);
        },          // pid callback
        0,          // timeout
        { lth_exec::execution_options::thread_safe,
          lth_exec::execution_options::create_detached_process,
          lth_exec::execution_options::merge_environment,
          lth_exec::execution_options::inherit_locale });  // options

    LOG_INFO("The task for the {1} has completed", request.prettyLabel());

    if (exec.exit_code == EXTERNAL_MODULE_FILE_ERROR_EC) {
        // This is unexpected. The output of the task will not be
        // available for future transaction status requests; we cannot
        // provide a reliable ActionResponse.
        std::string empty_label { lth_loc::translate("(empty)") };
        LOG_WARNING("The task process failed to write output on file for the {1}; "
                    "stdout: {2}; stderr: {3}",
                    request.prettyLabel(),
                    (exec.output.empty() ? empty_label : exec.output),
                    (exec.error.empty() ? empty_label : exec.error));
        throw Module::ProcessingError {
            lth_loc::translate("failed to write output on file") };
    }

    // Wait a bit to relax the requirement for the exitcode file being
    // written before the output ones, when the process completes
    LOG_TRACE("Waiting {1} ms before retrieving the output of {2}",
              OUTPUT_DELAY_MS, request.prettyLabel());
    pcp_util::this_thread::sleep_for(
        pcp_util::chrono::milliseconds(OUTPUT_DELAY_MS));

    // Stdout / stderr output should be on file; read it
    response.output = storage_.getOutput(request.transactionId(), exec.exit_code);
    ExternalModule::processOutputAndUpdateMetadata(response);
    return response;
}

ActionResponse ExternalModule::callAction(const ActionRequest& request)
{
    if (request.type() == RequestType::Blocking) {
        return callBlockingAction(request);
    } else {
        // Guranteed by Configuration
        assert(!request.resultsDir().empty());
        return callNonBlockingAction(request);
    }
}

}  // namespace PXPAgent
<|endoftext|>


<commit_before>#include "image.h"
#include "body.h"
#include "font.h"
#include "units.h"
#include "linkedlist.h"
#include "misc.h"

#include <fstream>
#include <pngwriter.h>

using namespace std;

//pngwriter png;

Image::Image(string filename, int w, int h, double _scale) {
	fileName = filename;
	width = w;
	height = h;
	scale = _scale;

	png = pngwriter(width, height, 0, filename.c_str());
}

void Image::Draw(int x, int y, int r, int g, int b) {
	double redValue = ((double)r / 255.0);
	double greenValue = ((double)g / 255.0);
	double blueValue = ((double)b / 255.0);

	png.plot(x, y, redValue, greenValue, blueValue);
}

void Image::DrawLine(int x1, int y1, int x2, int y2, int r, int g, int b) {
	double redValue = ((double)r / 255.0);
	double greenValue = ((double)g / 255.0);
	double blueValue = ((double)b / 255.0);

	png.line(x1, height - y1, x2, height - y2, redValue, greenValue, blueValue);
}

int Image::Scale(double coordinate, double scale) {
	int position = (int)(coordinate / AU * scale);
	return position;
}

void Image::DrawBody(double x, double y, double radius, int r, int g, int b) {
	int xScaled = (width / 2) + Scale(x, scale);
 	int yScaled = (height / 2) + Scale(y, scale);
 	int radiusScaled = Scale(radius, scale);

	bool xValid = xScaled < width && xScaled >= 0;
	bool yValid = yScaled < height && yScaled >= 0;

	if (xValid && yValid) {
		double redValue = ((double)r / 255.0);
		double greenValue = ((double)g / 255.0);
		double blueValue = ((double)b / 255.0);

		if (radiusScaled == 0) {
			Draw(xScaled, yScaled, 255, 255, 255); // White pixels show up the best on the screen
		}
		else {
			png.filledcircle(xScaled, yScaled, radiusScaled, redValue, greenValue, blueValue);
		}

		//Draw(xScaled, yScaled, r, g, b);
	}
}

void Image::DrawAllBodies(List bodyList, int r, int g, int b) {
	Body * body = bodyList.GetHead();
	while (body != NULL) {
		DrawBody(body->GetX(), body->GetY(), body->GetRadius(), r, g, b);
		body = body->next;
	}
}

void Image::DrawTextArray(int textArray [5][5], int xStart, int yStart, int r, int g, int b) {
	for (int y = 0; y < 5; y++)
	{
		for (int x = 0; x < 5; x++)
		{
			if (textArray[y][x] == 0)
			{
				png.plot(x + xStart, height - (y + yStart), 0.0, 0.0, 0.0);
			}
			else
			{
				png.plot(x + xStart, height - (y + yStart), ((double)r / 255.0), ((double)g / 255.0), ((double)b / 255.0));
			}
		}
	}
}

void Image::DrawText(string text, int x, int y, int r, int g, int b) {
	for (size_t i = 0; i < text.length(); i++)
	{
		int c = (int)i;

		// Handle Alphabet
		if (tolower(text[c]) >= 97 && tolower(text[c]) <= 122)
		{
			int index = tolower(text[c]) - 97;
			DrawTextArray(fontAlphabet[index], x, y, r, g, b);
		}

		// Handle Numbers
		else if (tolower(text[c]) >= 48 && tolower(text[c]) <= 57)
		{
			int index = tolower(text[c]) - 48;
			DrawTextArray(fontNumbers[index], x, y, r, g, b);
		}

		// Handle Punctuation
		else
		{
			switch (text[c])
			{
			case '.':
				DrawTextArray(fontPERIOD, x, y, r, g, b);
				break;
			case ':':
				DrawTextArray(fontCOLON, x, y, r, g, b);
				break;
			case '-':
				DrawTextArray(fontHYPHEN, x, y, r, g, b);
				break;
			case '/':
				DrawTextArray(fontSLASH, x, y, r, g, b);
				break;

			default:
				break;
			}
		}

		x += fontWidth + kerning;
	}
}

void Image::DrawScale(double scale, int x, int y, int r, int g, int b) {
	if (scale >= 3.0) {
		// Long enough to a line
		double distanceOfScale = 1.0;
		string scaleString = "1 AU";

		// Check if line + text will fit on screen
		while (x + scale + 10 + (6 * scaleString.length()) >= width) {
			scale /= 10;
			distanceOfScale /= 10;
			scaleString = RemoveTrailingZeroes(to_string(distanceOfScale)) + " AU";
		}

		DrawLine(x, y, x + scale, y, r, g, b);
		Draw(x, height - y + 1, r, g, b);
		Draw(x + scale, height - y + 1, r, g, b);

		DrawText(scaleString.c_str(), x + scale + 5, y - 2, r, g, b);
	}
	else {
		// Not long enough - just write a message
		string scaleText = "SCALE: " + to_string(scale) + " PX/AU";
		DrawText(scaleText.c_str(), x, y - 2, r, g, b);
	}
}

void Image::Save() {
	png.close();
}
<commit_msg>Scale line now expands when zooming out<commit_after>#include "image.h"
#include "body.h"
#include "font.h"
#include "units.h"
#include "linkedlist.h"
#include "misc.h"

#include <fstream>
#include <pngwriter.h>

using namespace std;

//pngwriter png;

Image::Image(string filename, int w, int h, double _scale) {
	fileName = filename;
	width = w;
	height = h;
	scale = _scale;

	png = pngwriter(width, height, 0, filename.c_str());
}

void Image::Draw(int x, int y, int r, int g, int b) {
	double redValue = ((double)r / 255.0);
	double greenValue = ((double)g / 255.0);
	double blueValue = ((double)b / 255.0);

	png.plot(x, y, redValue, greenValue, blueValue);
}

void Image::DrawLine(int x1, int y1, int x2, int y2, int r, int g, int b) {
	double redValue = ((double)r / 255.0);
	double greenValue = ((double)g / 255.0);
	double blueValue = ((double)b / 255.0);

	png.line(x1, height - y1, x2, height - y2, redValue, greenValue, blueValue);
}

int Image::Scale(double coordinate, double scale) {
	int position = (int)(coordinate / AU * scale);
	return position;
}

void Image::DrawBody(double x, double y, double radius, int r, int g, int b) {
	int xScaled = (width / 2) + Scale(x, scale);
 	int yScaled = (height / 2) + Scale(y, scale);
 	int radiusScaled = Scale(radius, scale);

	bool xValid = xScaled < width && xScaled >= 0;
	bool yValid = yScaled < height && yScaled >= 0;

	if (xValid && yValid) {
		double redValue = ((double)r / 255.0);
		double greenValue = ((double)g / 255.0);
		double blueValue = ((double)b / 255.0);

		if (radiusScaled == 0) {
			Draw(xScaled, yScaled, 255, 255, 255); // White pixels show up the best on the screen
		}
		else {
			png.filledcircle(xScaled, yScaled, radiusScaled, redValue, greenValue, blueValue);
		}

		//Draw(xScaled, yScaled, r, g, b);
	}
}

void Image::DrawAllBodies(List bodyList, int r, int g, int b) {
	Body * body = bodyList.GetHead();
	while (body != NULL) {
		DrawBody(body->GetX(), body->GetY(), body->GetRadius(), r, g, b);
		body = body->next;
	}
}

void Image::DrawTextArray(int textArray [5][5], int xStart, int yStart, int r, int g, int b) {
	for (int y = 0; y < 5; y++)
	{
		for (int x = 0; x < 5; x++)
		{
			if (textArray[y][x] == 0)
			{
				png.plot(x + xStart, height - (y + yStart), 0.0, 0.0, 0.0);
			}
			else
			{
				png.plot(x + xStart, height - (y + yStart), ((double)r / 255.0), ((double)g / 255.0), ((double)b / 255.0));
			}
		}
	}
}

void Image::DrawText(string text, int x, int y, int r, int g, int b) {
	for (size_t i = 0; i < text.length(); i++)
	{
		int c = (int)i;

		// Handle Alphabet
		if (tolower(text[c]) >= 97 && tolower(text[c]) <= 122)
		{
			int index = tolower(text[c]) - 97;
			DrawTextArray(fontAlphabet[index], x, y, r, g, b);
		}

		// Handle Numbers
		else if (tolower(text[c]) >= 48 && tolower(text[c]) <= 57)
		{
			int index = tolower(text[c]) - 48;
			DrawTextArray(fontNumbers[index], x, y, r, g, b);
		}

		// Handle Punctuation
		else
		{
			switch (text[c])
			{
			case '.':
				DrawTextArray(fontPERIOD, x, y, r, g, b);
				break;
			case ':':
				DrawTextArray(fontCOLON, x, y, r, g, b);
				break;
			case '-':
				DrawTextArray(fontHYPHEN, x, y, r, g, b);
				break;
			case '/':
				DrawTextArray(fontSLASH, x, y, r, g, b);
				break;

			default:
				break;
			}
		}

		x += fontWidth + kerning;
	}
}

void Image::DrawScale(double scale, int x, int y, int r, int g, int b) {
	double distanceOfScale = 1.0;
	string scaleString = "1.0 AU";

	if (scale >= 3.0) {
		// Long enough to a line
		// Check if line + text will fit on screen
		while (x + scale + 10 + (6 * scaleString.length()) >= width) {
			scale /= 10;
			distanceOfScale /= 10;
			scaleString = RemoveTrailingZeroes(to_string(distanceOfScale)) + " AU";
		}

		DrawLine(x, y, x + scale, y, r, g, b);
		Draw(x, height - y + 1, r, g, b);
		Draw(x + scale, height - y + 1, r, g, b);

		DrawText(scaleString.c_str(), x + scale + 5, y - 2, r, g, b);
	}
	else {
		// Too short - must extend to fill screen
		scale *= 100;
		distanceOfScale *= 100;
		scaleString = RemoveTrailingZeroes(to_string(distanceOfScale)) + " AU";

		DrawLine(x, y, x + scale, y, r, g, b);
		Draw(x, height - y + 1, r, g, b);
		Draw(x + scale, height - y + 1, r, g, b);

		DrawText(scaleString.c_str(), x + scale + 5, y - 2, r, g, b);
	}
}

void Image::Save() {
	png.close();
}
<|endoftext|>