<commit_before>//
// Copyright (C) 2007-2008 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2007-2008 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// Author: Dan Petrie <dpetrie AT SIPez DOT com>

// SYSTEM INCLUDES
#include <assert.h>

// APPLICATION INCLUDES
#include <os/OsSysLog.h>
#include <mp/MpInputDeviceManager.h>
#include <mp/MprFromInputDevice.h>
#include <mp/MpMisc.h>
#include <mp/MpResampler.h>

#ifdef RTL_ENABLED
#include <rtl_macro.h>
#else
#define RTL_BLOCK(x)
#define RTL_EVENT(x,y)
#endif

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
// DEFINES
#define DEBUG_PRINT
#undef  DEBUG_PRINT

// MACROS
#ifdef DEBUG_PRINT // [
#  define debugPrintf    printf
#else  // DEBUG_PRINT ][
static void debugPrintf(...) {}
#endif // DEBUG_PRINT ]

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
MprFromInputDevice::MprFromInputDevice(const UtlString& rName,
                                      MpInputDeviceManager* deviceManager,
                                      MpInputDeviceHandle deviceId)
: MpAudioResource(rName,
                  0, 0, /* inputs */
                  1, 1  /* outputs */)
, mpInputDeviceManager(deviceManager)
, mFrameTimeInitialized(FALSE)
, mPreviousFrameTime(0)
, mDeviceId(deviceId)
, mpResampler(MpResamplerBase::createResampler(1, 8000, 8000))
{
}

// Destructor
MprFromInputDevice::~MprFromInputDevice()
{
   delete mpResampler;
}

/* ============================ MANIPULATORS ============================== */

/* ============================ ACCESSORS ================================= */

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

UtlBoolean MprFromInputDevice::doProcessFrame(MpBufPtr inBufs[],
                                             MpBufPtr outBufs[],
                                             int inBufsSize,
                                             int outBufsSize,
                                             UtlBoolean isEnabled,
                                             int samplesPerFrame,
                                             int samplesPerSecond)
{
   // NOTE: Logic to react to frequent starvation is missing.
   RTL_BLOCK("MprFromInputDevice::doProcessFrame");

   assert(mpInputDeviceManager);

   if (!isEnabled)
   {
      return TRUE;
   }

   // Milliseconds per frame:
   int frameTimeInterval = samplesPerFrame * 1000 / samplesPerSecond;

   if (!mFrameTimeInitialized)
   {
      // Start with a frame behind.  Possible need smarter
      // decision for starting.
      mPreviousFrameTime = mpInputDeviceManager->getCurrentFrameTime(mDeviceId);
//      mPreviousFrameTime -= (5 * frameTimeInterval);
   }

   mPreviousFrameTime += frameTimeInterval;

   MpAudioBufPtr inAudioBuffer;
   unsigned int numFramesNotPlayed = 0;
   unsigned int numFramedBufferedBehind = 0;
   MpFrameTime  frameToFetch = 0;

   // Use temp variable for frame time to prevent frame time drift in case
   // of device hiccup.
   frameToFetch = mPreviousFrameTime;

   OsStatus getResult = mpInputDeviceManager->getFrame(mDeviceId,
                                                       frameToFetch,
                                                       inAudioBuffer,
                                                       numFramesNotPlayed,
                                                       numFramedBufferedBehind);

   debugPrintf("MprFromInputDevice::doProcessFrame()"
               " frameToFetch=%d, getResult=%d, numFramesNotPlayed=%d, numFramedBufferedBehind=%d\n",
               frameToFetch, getResult, numFramesNotPlayed, numFramedBufferedBehind);

   if(getResult != OS_SUCCESS)
   {
      int numAdvances = 0;
      while (getResult == OS_NOT_FOUND && numFramedBufferedBehind == 0 && numFramesNotPlayed > 0)
      {
         debugPrintf("+ %d numFramesNotPlayed=%d, numFramedBufferedBehind=%d\n",
                     mPreviousFrameTime, numFramesNotPlayed, numFramedBufferedBehind);
         mPreviousFrameTime += frameTimeInterval;
         frameToFetch = mPreviousFrameTime;
         getResult =
            mpInputDeviceManager->getFrame(mDeviceId,
                                           frameToFetch,
                                           inAudioBuffer,
                                           numFramesNotPlayed,
                                           numFramedBufferedBehind);
         numAdvances++;
         RTL_EVENT("MprFromInputDevice::advance", numAdvances);
      }
      numAdvances = 0;
      RTL_EVENT("MprFromInputDevice::advance", numAdvances);
      while (getResult == OS_NOT_FOUND && numFramedBufferedBehind > 0 && numFramesNotPlayed == 0)
      {
         debugPrintf("- %d numFramesNotPlayed=%d, numFramedBufferedBehind=%d\n",
                     mPreviousFrameTime, numFramesNotPlayed, numFramedBufferedBehind);
         mPreviousFrameTime -= frameTimeInterval;
         frameToFetch = mPreviousFrameTime;
         getResult =
            mpInputDeviceManager->getFrame(mDeviceId,
                                           frameToFetch,
                                           inAudioBuffer,
                                           numFramesNotPlayed,
                                           numFramedBufferedBehind);
         numAdvances--;
         RTL_EVENT("MprFromInputDevice::advance", numAdvances);
      }
      numAdvances = 0;
      RTL_EVENT("MprFromInputDevice::advance", numAdvances);
   }

   if (!mFrameTimeInitialized)
   {
      if (getResult == OS_SUCCESS)
      {
         mPreviousFrameTime = frameToFetch;
         mFrameTimeInitialized = TRUE;
      }
   }

   // Get the name of the device we're writing to.
   UtlString devName = "Unknown device";
   mpInputDeviceManager->getDeviceName(mDeviceId, devName);

   uint32_t devSampleRate = 0;
   OsStatus stat = mpInputDeviceManager->getDeviceSamplesPerSec(mDeviceId, devSampleRate);
   assert(stat == OS_SUCCESS);
   if(stat != OS_SUCCESS)
   {
      OsSysLog::add(FAC_MP, PRI_ERR, "MprFromInputDevice::doProcessFrame "
         "- Couldn't get device sample rate from input device manager!  "
         "Device - \"%s\"", devName.data());
      return FALSE;
   }

   // Check to see if the resampler needs it's rate adjusted.
   if(mpResampler->getInputRate() != devSampleRate)
      mpResampler->setInputRate(devSampleRate);
   if(mpResampler->getOutputRate() != samplesPerSecond)
      mpResampler->setOutputRate(samplesPerSecond);

   MpAudioBufPtr resampledBuffer;
   // Try to resample and replace.
   // If the function determines resampling is unnecessary, then it will just
   // leave the buffer pointer unchanged, and return OS_SUCCESS, which is what
   // we want.
   if(mpResampler->resampleBufPtr(inAudioBuffer, resampledBuffer,
         devSampleRate, samplesPerSecond, devName) != OS_SUCCESS)
   {
      // Error messages have already been logged. No need to do so here.
      return FALSE;
   }

   // Set the output buffer ptr to the device's audio (either resampled or not
   // if it was not needed)
   // To optimize for speed a bit, we use MpBufPtr's swap() method instead of
   // assignment -- make sure we don't use resampledBuffer or inAudioBuffer
   // after this!
   outBufs[0].swap((resampledBuffer.isValid()) ? resampledBuffer : inAudioBuffer);

   return getResult;
}

/* ============================ FUNCTIONS ================================= */

<commit_msg>Minor cleanup of positioning code in MprFromInputDevice.cpp<commit_after>//
// Copyright (C) 2007-2008 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2007-2008 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// Author: Dan Petrie <dpetrie AT SIPez DOT com>

// SYSTEM INCLUDES
#include <assert.h>

// APPLICATION INCLUDES
#include <os/OsSysLog.h>
#include <mp/MpInputDeviceManager.h>
#include <mp/MprFromInputDevice.h>
#include <mp/MpMisc.h>
#include <mp/MpResampler.h>

#ifdef RTL_ENABLED
#include <rtl_macro.h>
#else
#define RTL_BLOCK(x)
#define RTL_EVENT(x,y)
#endif

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
// DEFINES
#define DEBUG_PRINT
#undef  DEBUG_PRINT

// MACROS
#ifdef DEBUG_PRINT // [
#  define debugPrintf    printf
#else  // DEBUG_PRINT ][
static void debugPrintf(...) {}
#endif // DEBUG_PRINT ]

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
MprFromInputDevice::MprFromInputDevice(const UtlString& rName,
                                      MpInputDeviceManager* deviceManager,
                                      MpInputDeviceHandle deviceId)
: MpAudioResource(rName,
                  0, 0, /* inputs */
                  1, 1  /* outputs */)
, mpInputDeviceManager(deviceManager)
, mFrameTimeInitialized(FALSE)
, mPreviousFrameTime(0)
, mDeviceId(deviceId)
, mpResampler(MpResamplerBase::createResampler(1, 8000, 8000))
{
}

// Destructor
MprFromInputDevice::~MprFromInputDevice()
{
   delete mpResampler;
}

/* ============================ MANIPULATORS ============================== */

/* ============================ ACCESSORS ================================= */

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

UtlBoolean MprFromInputDevice::doProcessFrame(MpBufPtr inBufs[],
                                             MpBufPtr outBufs[],
                                             int inBufsSize,
                                             int outBufsSize,
                                             UtlBoolean isEnabled,
                                             int samplesPerFrame,
                                             int samplesPerSecond)
{
   // NOTE: Logic to react to frequent starvation is missing.
   RTL_BLOCK("MprFromInputDevice::doProcessFrame");

   assert(mpInputDeviceManager);

   if (!isEnabled)
   {
      return TRUE;
   }

   // Milliseconds per frame:
   int frameTimeInterval = samplesPerFrame * 1000 / samplesPerSecond;

   if (!mFrameTimeInitialized)
   {
      mPreviousFrameTime = mpInputDeviceManager->getCurrentFrameTime(mDeviceId);
//      mPreviousFrameTime -= (5 * frameTimeInterval);
   }
   else
   {
      mPreviousFrameTime += frameTimeInterval;
   }

   MpAudioBufPtr inAudioBuffer;
   unsigned int numFramesNotPlayed = 0;
   unsigned int numFramedBufferedBehind = 0;
   MpFrameTime  frameToFetch = 0;

   // Use temp variable for frame time to prevent frame time drift in case
   // of device hiccup.
   frameToFetch = mPreviousFrameTime;

   OsStatus getResult = mpInputDeviceManager->getFrame(mDeviceId,
                                                       frameToFetch,
                                                       inAudioBuffer,
                                                       numFramesNotPlayed,
                                                       numFramedBufferedBehind);

   debugPrintf("MprFromInputDevice::doProcessFrame()"
               " frameToFetch=%d, getResult=%d, numFramesNotPlayed=%d, numFramedBufferedBehind=%d\n",
               frameToFetch, getResult, numFramesNotPlayed, numFramedBufferedBehind);

   if(getResult != OS_SUCCESS)
   {
      int numAdvances = 0;
      while (getResult == OS_NOT_FOUND && numFramedBufferedBehind == 0 && numFramesNotPlayed > 0)
      {
         debugPrintf("+ %d numFramesNotPlayed=%d, numFramedBufferedBehind=%d\n",
                     mPreviousFrameTime, numFramesNotPlayed, numFramedBufferedBehind);
         mPreviousFrameTime += frameTimeInterval;
         frameToFetch = mPreviousFrameTime;
         getResult =
            mpInputDeviceManager->getFrame(mDeviceId,
                                           frameToFetch,
                                           inAudioBuffer,
                                           numFramesNotPlayed,
                                           numFramedBufferedBehind);
         numAdvances++;
         RTL_EVENT("MprFromInputDevice::advance", numAdvances);
      }
      numAdvances = 0;
      RTL_EVENT("MprFromInputDevice::advance", numAdvances);
      while (getResult == OS_NOT_FOUND && numFramedBufferedBehind > 0 && numFramesNotPlayed == 0)
      {
         debugPrintf("- %d numFramesNotPlayed=%d, numFramedBufferedBehind=%d\n",
                     mPreviousFrameTime, numFramesNotPlayed, numFramedBufferedBehind);
         mPreviousFrameTime -= frameTimeInterval;
         frameToFetch = mPreviousFrameTime;
         getResult =
            mpInputDeviceManager->getFrame(mDeviceId,
                                           frameToFetch,
                                           inAudioBuffer,
                                           numFramesNotPlayed,
                                           numFramedBufferedBehind);
         numAdvances--;
         RTL_EVENT("MprFromInputDevice::advance", numAdvances);
      }
      numAdvances = 0;
      RTL_EVENT("MprFromInputDevice::advance", numAdvances);
   }

   if (!mFrameTimeInitialized)
   {
      if (getResult == OS_SUCCESS)
      {
         mPreviousFrameTime = frameToFetch;
         mFrameTimeInitialized = TRUE;
      }
   }

   // Get the name of the device we're writing to.
   UtlString devName = "Unknown device";
   mpInputDeviceManager->getDeviceName(mDeviceId, devName);

   uint32_t devSampleRate = 0;
   OsStatus stat = mpInputDeviceManager->getDeviceSamplesPerSec(mDeviceId, devSampleRate);
   assert(stat == OS_SUCCESS);
   if(stat != OS_SUCCESS)
   {
      OsSysLog::add(FAC_MP, PRI_ERR, "MprFromInputDevice::doProcessFrame "
         "- Couldn't get device sample rate from input device manager!  "
         "Device - \"%s\"", devName.data());
      return FALSE;
   }

   // Check to see if the resampler needs it's rate adjusted.
   if(mpResampler->getInputRate() != devSampleRate)
      mpResampler->setInputRate(devSampleRate);
   if(mpResampler->getOutputRate() != samplesPerSecond)
      mpResampler->setOutputRate(samplesPerSecond);

   MpAudioBufPtr resampledBuffer;
   // Try to resample and replace.
   // If the function determines resampling is unnecessary, then it will just
   // leave the buffer pointer unchanged, and return OS_SUCCESS, which is what
   // we want.
   if(mpResampler->resampleBufPtr(inAudioBuffer, resampledBuffer,
         devSampleRate, samplesPerSecond, devName) != OS_SUCCESS)
   {
      // Error messages have already been logged. No need to do so here.
      return FALSE;
   }

   // Set the output buffer ptr to the device's audio (either resampled or not
   // if it was not needed)
   // To optimize for speed a bit, we use MpBufPtr's swap() method instead of
   // assignment -- make sure we don't use resampledBuffer or inAudioBuffer
   // after this!
   outBufs[0].swap((resampledBuffer.isValid()) ? resampledBuffer : inAudioBuffer);

   return getResult;
}

/* ============================ FUNCTIONS ================================= */

<|endoftext|>


<commit_before>#include "mutator.hpp"

#include <iostream>
#include <fstream>

namespace mtt
{

    Mutator::Mutator()
    {
        std::random_device rd;
        gen = std::mt19937(rd());

        letter = std::uniform_int_distribution<>{1, 1000000000};

        for (std::size_t i = 0; i < probabilities.size(); ++i)
            for (std::size_t j = 0; j < probabilities.size(); ++j)
                for (std::size_t k = 0; k < probabilities.size(); ++k)
                    for (std::size_t l = 0; l < probabilities.size(); ++l)
                        probabilities[i][j][k][l] = letter(gen)/1000000000.0;
    }

    Mutator::Mutator(const std::string & filename)
    {
        std::ifstream ifile(filename);

        probabilities = {0};

        std::size_t count = 3;
        char c = ifile.get();
        auto prevprevprevindex = c == ' ' ? 26 : static_cast<int>(c) - 97;
        c = ifile.get();
        auto prevprevindex = c == ' ' ? 26 : static_cast<int>(c) - 97;
        c = ifile.get();
        auto previndex = c == ' ' ? 26 : static_cast<int>(c) - 97;

        while (ifile.get(c)) {
            count++;
            auto index = c == ' ' ? 26 : static_cast<int>(c) - 97;
            probabilities[prevprevprevindex][prevprevindex][previndex][index]++;
            prevprevprevindex = prevprevindex;
            prevprevindex = previndex;
            previndex = index;
        }

        for (std::size_t i = 0; i < probabilities.size(); ++i)
            for (std::size_t j = 0; j < probabilities.size(); ++j)
                for (std::size_t k = 0; k < probabilities.size(); ++k)
                    for (std::size_t l = 0; l < probabilities.size(); ++l)
                    {
                        probabilities[i][j][k][l] /= count;
                    }

    }

    std::vector<char> Mutator::createText(const std::size_t n)
    {
        std::vector<char> text;

        int prev,prevprev,prevprevprev;

        // First char
        float currLetter = letter(gen)/1000000000.0;
        std::cout << currLetter << std::endl;
        std::array<float,27> cumuledProbabilities{0};
        for (std::size_t i = 0; i < probabilities.size(); i++)
        {
            float proba = 0;
            for (std::size_t j = 0; j < probabilities.size(); j++)
            {
                for (std::size_t k = 0; k < probabilities.size(); k++)
                {
                    for (std::size_t l = 0; l < probabilities.size(); l++)
                        proba += probabilities[i][j][k][l];
                }
            }
            std::cout << proba << std::endl;
            cumuledProbabilities[i] = proba;
            std::cout << cumuledProbabilities[i] << std::endl;
        }
        for (std::size_t i = 1; i < cumuledProbabilities.size(); i++)
        {
            cumuledProbabilities[i] += cumuledProbabilities[i-1];
            std::cout << cumuledProbabilities[i] << std::endl;
        }
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] /= cumuledProbabilities.at(cumuledProbabilities.size()-1);
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
        {
            std::cout << cumuledProbabilities[i] << std::endl;
            if (cumuledProbabilities[i] > currLetter)
            {
                text.push_back(i);
                prev = i;
                break;
                std::cout << i << std::endl;
            }
        }

        // Second char
        currLetter = letter(gen)/1000000000.0;
        cumuledProbabilities = {0};
        for (std::size_t i = 0; i < probabilities.size(); i++)
        {
            float proba = 0;
            for (std::size_t j = 0; j < probabilities.size(); j++)
            {
                for (std::size_t k = 0; k < probabilities.size(); k++)
                {
                    proba += probabilities[prev][i][j][k];
                }
            }
            cumuledProbabilities[i] = proba;
        }
        for (std::size_t i = 1; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] += cumuledProbabilities[i-1];
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] /= cumuledProbabilities.at(cumuledProbabilities.size()-1);
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
        {
            if (cumuledProbabilities[i] > currLetter)
            {
                text.push_back(i);
                prevprev = i;
                break;
            }
        }

        // Third char
        currLetter = letter(gen)/1000000000.0;
        cumuledProbabilities = {0};
        for (std::size_t j = 0; j < probabilities.size(); j++)
        {
            float proba = 0;
            for (std::size_t k = 0; k < probabilities.size(); k++)
            {
                proba += probabilities[prev][prevprev][j][k];
            }
            cumuledProbabilities[j] = proba;
        }
        for (std::size_t i = 1; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] += cumuledProbabilities[i-1];
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] /= cumuledProbabilities.at(cumuledProbabilities.size()-1);
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
        {
            if (cumuledProbabilities[i] > currLetter)
            {
                text.push_back(i);
                prevprevprev = i;
                break;
            }
        }

        // Next chars
        while(text.size() < 10000)
        {
            int prevprevprevprev = 0;
            std::array<float,27> cumuledProbabilities{0};
            currLetter = letter(gen)/1000000000.0;
            cumuledProbabilities[0] = probabilities[prevprevprev][prevprev][prev][0];
            for (std::size_t i = 1; i < probabilities.size(); i++)
                cumuledProbabilities[i] = cumuledProbabilities[i-1] + probabilities[prevprevprev][prevprev][prev][i];
            if (cumuledProbabilities.at(cumuledProbabilities.size()-1) == 0)
            {
                text.pop_back();
                prev = prevprev;
                prevprev = prevprevprev;
                prevprevprev = prevprevprevprev;
                continue;
            }
            for (std::size_t i = 0; i < probabilities.size(); i++)
                cumuledProbabilities[i] /=cumuledProbabilities.at(cumuledProbabilities.size()-1);
            for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
            {
                if (cumuledProbabilities[i] >= currLetter && (i != 26 || prev != 26))
                {
                    text.push_back(i);
                    prevprevprevprev = prevprevprev;
                    prevprevprev = prevprev;
                    prevprev = prev;
                    prev = i;
                    break;
                }
            }
        }

        return text;
    }
}

std::ostream& operator<<(std::ostream& os, const std::vector<char>& text)
{
    for (std::size_t n = 0; n < text.size(); ++n)
    {
        if (text.at(n) == 26)
        {
            os <<  " ";
        }
        else
        {
            os << (char) (text.at(n) + 97) ;
        }
    }

    return os;
}

<commit_msg>Deleted some useless prints<commit_after>#include "mutator.hpp"

#include <iostream>
#include <fstream>

namespace mtt
{

    Mutator::Mutator()
    {
        std::random_device rd;
        gen = std::mt19937(rd());

        letter = std::uniform_int_distribution<>{1, 1000000000};

        for (std::size_t i = 0; i < probabilities.size(); ++i)
            for (std::size_t j = 0; j < probabilities.size(); ++j)
                for (std::size_t k = 0; k < probabilities.size(); ++k)
                    for (std::size_t l = 0; l < probabilities.size(); ++l)
                        probabilities[i][j][k][l] = letter(gen)/1000000000.0;
    }

    Mutator::Mutator(const std::string & filename)
    {
        std::ifstream ifile(filename);

        probabilities = {0};

        std::size_t count = 3;
        char c = ifile.get();
        auto prevprevprevindex = c == ' ' ? 26 : static_cast<int>(c) - 97;
        c = ifile.get();
        auto prevprevindex = c == ' ' ? 26 : static_cast<int>(c) - 97;
        c = ifile.get();
        auto previndex = c == ' ' ? 26 : static_cast<int>(c) - 97;

        while (ifile.get(c)) {
            count++;
            auto index = c == ' ' ? 26 : static_cast<int>(c) - 97;
            probabilities[prevprevprevindex][prevprevindex][previndex][index]++;
            prevprevprevindex = prevprevindex;
            prevprevindex = previndex;
            previndex = index;
        }

        for (std::size_t i = 0; i < probabilities.size(); ++i)
            for (std::size_t j = 0; j < probabilities.size(); ++j)
                for (std::size_t k = 0; k < probabilities.size(); ++k)
                    for (std::size_t l = 0; l < probabilities.size(); ++l)
                    {
                        probabilities[i][j][k][l] /= count;
                    }

    }

    std::vector<char> Mutator::createText(const std::size_t n)
    {
        std::vector<char> text;

        int prev,prevprev,prevprevprev;

        // First char
        float currLetter = letter(gen)/1000000000.0;
        std::array<float,27> cumuledProbabilities{0};
        for (std::size_t i = 0; i < probabilities.size(); i++)
        {
            float proba = 0;
            for (std::size_t j = 0; j < probabilities.size(); j++)
            {
                for (std::size_t k = 0; k < probabilities.size(); k++)
                {
                    for (std::size_t l = 0; l < probabilities.size(); l++)
                        proba += probabilities[i][j][k][l];
                }
            }
            cumuledProbabilities[i] = proba;
        }
        for (std::size_t i = 1; i < cumuledProbabilities.size(); i++)
        {
            cumuledProbabilities[i] += cumuledProbabilities[i-1];
        }
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] /= cumuledProbabilities.at(cumuledProbabilities.size()-1);
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
        {
            if (cumuledProbabilities[i] > currLetter)
            {
                text.push_back(i);
                prev = i;
                break;
            }
        }

        // Second char
        currLetter = letter(gen)/1000000000.0;
        cumuledProbabilities = {0};
        for (std::size_t i = 0; i < probabilities.size(); i++)
        {
            float proba = 0;
            for (std::size_t j = 0; j < probabilities.size(); j++)
            {
                for (std::size_t k = 0; k < probabilities.size(); k++)
                {
                    proba += probabilities[prev][i][j][k];
                }
            }
            cumuledProbabilities[i] = proba;
        }
        for (std::size_t i = 1; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] += cumuledProbabilities[i-1];
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] /= cumuledProbabilities.at(cumuledProbabilities.size()-1);
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
        {
            if (cumuledProbabilities[i] > currLetter)
            {
                text.push_back(i);
                prevprev = i;
                break;
            }
        }

        // Third char
        currLetter = letter(gen)/1000000000.0;
        cumuledProbabilities = {0};
        for (std::size_t j = 0; j < probabilities.size(); j++)
        {
            float proba = 0;
            for (std::size_t k = 0; k < probabilities.size(); k++)
            {
                proba += probabilities[prev][prevprev][j][k];
            }
            cumuledProbabilities[j] = proba;
        }
        for (std::size_t i = 1; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] += cumuledProbabilities[i-1];
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
            cumuledProbabilities[i] /= cumuledProbabilities.at(cumuledProbabilities.size()-1);
        for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
        {
            if (cumuledProbabilities[i] > currLetter)
            {
                text.push_back(i);
                prevprevprev = i;
                break;
            }
        }

        // Next chars
        while(text.size() < 10000)
        {
            int prevprevprevprev = 0;
            std::array<float,27> cumuledProbabilities{0};
            currLetter = letter(gen)/1000000000.0;
            cumuledProbabilities[0] = probabilities[prevprevprev][prevprev][prev][0];
            for (std::size_t i = 1; i < probabilities.size(); i++)
                cumuledProbabilities[i] = cumuledProbabilities[i-1] + probabilities[prevprevprev][prevprev][prev][i];
            if (cumuledProbabilities.at(cumuledProbabilities.size()-1) == 0)
            {
                text.pop_back();
                prev = prevprev;
                prevprev = prevprevprev;
                prevprevprev = prevprevprevprev;
                continue;
            }
            for (std::size_t i = 0; i < probabilities.size(); i++)
                cumuledProbabilities[i] /=cumuledProbabilities.at(cumuledProbabilities.size()-1);
            for (std::size_t i = 0; i < cumuledProbabilities.size(); i++)
            {
                if (cumuledProbabilities[i] >= currLetter && (i != 26 || prev != 26))
                {
                    text.push_back(i);
                    prevprevprevprev = prevprevprev;
                    prevprevprev = prevprev;
                    prevprev = prev;
                    prev = i;
                    break;
                }
            }
        }

        return text;
    }
}

std::ostream& operator<<(std::ostream& os, const std::vector<char>& text)
{
    for (std::size_t n = 0; n < text.size(); ++n)
    {
        if (text.at(n) == 26)
        {
            os <<  " ";
        }
        else
        {
            os << (char) (text.at(n) + 97) ;
        }
    }

    return os;
}

<|endoftext|>


<commit_before>/*
 * server_memory_test.cpp - Kurento Media Server
 *
 * Copyright (C) 2013 Kurento
 * Contact: Miguel París Díaz <mparisdiaz@gmail.com>
 * Contact: José Antonio Santos Cadenas <santoscadenas@kurento.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "server_test_base.hpp"
#include <boost/test/unit_test.hpp>

#include "memory.hpp"
#include "mediaServer_constants.h"

#include <gst/gst.h>

using namespace kurento;

using namespace kurento;

#define GST_CAT_DEFAULT _server_memory_test_
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "server_memory_test"

#define ITERATIONS 10000
#define MEMORY_TOLERANCE 1024

BOOST_FIXTURE_TEST_SUITE ( server_memory_test_suite, F )

BOOST_AUTO_TEST_CASE ( create_media_manager_memory_test )
{
  MediaObject mediaManager = MediaObject();
  MediaObject mo = MediaObject();
  int i, maxMemorySize, currentMemorySize;

  BOOST_REQUIRE_MESSAGE (initialized, "Cannot connect to the server");
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);

  client->addHandlerAddress (0, "localhost", 2323);

  for (i = 0; i < ITERATIONS; i++) {
    client->createMediaManager (mediaManager, 0);
    client->release (mediaManager);

    if (i == 0) {
      maxMemorySize = get_data_memory (pid) + MEMORY_TOLERANCE;
      GST_INFO ("MAX memory size: %d", maxMemorySize);
    }

    if (i % 100 == 0) {
      currentMemorySize = get_data_memory (pid);
      GST_INFO ("Memory size: %d", currentMemorySize);
      BOOST_REQUIRE (currentMemorySize <= maxMemorySize);
    }
  }
}

BOOST_AUTO_TEST_CASE ( create_rtp_end_point_memory_test )
{
  MediaObject mediaManager = MediaObject();
  MediaObject mo = MediaObject();
  int i, maxMemorySize, currentMemorySize;

  BOOST_REQUIRE_MESSAGE (initialized, "Cannot connect to the server");
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);

  client->addHandlerAddress (0, "localhost", 2323);

  for (i = 0; i < ITERATIONS; i++) {
    client->createMediaManager (mediaManager, 0);
    client->createSdpEndPoint (mo, mediaManager, SdpEndPointType::type::RTP_END_POINT);
    client->release (mediaManager);

    if (i == 0) {
      maxMemorySize = get_data_memory (pid) + MEMORY_TOLERANCE;
      GST_INFO ("MAX memory size: %d", maxMemorySize);
    }

    if (i % 100 == 0) {
      currentMemorySize = get_data_memory (pid);
      GST_INFO ("Memory size: %d", currentMemorySize);
      BOOST_REQUIRE (currentMemorySize <= maxMemorySize);
    }
  }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Add memory test for zbar filter creation<commit_after>/*
 * server_memory_test.cpp - Kurento Media Server
 *
 * Copyright (C) 2013 Kurento
 * Contact: Miguel París Díaz <mparisdiaz@gmail.com>
 * Contact: José Antonio Santos Cadenas <santoscadenas@kurento.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "server_test_base.hpp"
#include <boost/test/unit_test.hpp>

#include "memory.hpp"
#include "mediaServer_constants.h"

#include <gst/gst.h>

using namespace kurento;

using namespace kurento;

#define GST_CAT_DEFAULT _server_memory_test_
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "server_memory_test"

#define ITERATIONS 10000
#define MEMORY_TOLERANCE 1024

BOOST_FIXTURE_TEST_SUITE ( server_memory_test_suite, F )

BOOST_AUTO_TEST_CASE ( create_media_manager_memory_test )
{
  MediaObject mediaManager = MediaObject();
  MediaObject mo = MediaObject();
  int i, maxMemorySize, currentMemorySize;

  BOOST_REQUIRE_MESSAGE (initialized, "Cannot connect to the server");
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);

  client->addHandlerAddress (0, "localhost", 2323);

  for (i = 0; i < ITERATIONS; i++) {
    client->createMediaManager (mediaManager, 0);
    client->release (mediaManager);

    if (i == 0) {
      maxMemorySize = get_data_memory (pid) + MEMORY_TOLERANCE;
      GST_INFO ("MAX memory size: %d", maxMemorySize);
    }

    if (i % 100 == 0) {
      currentMemorySize = get_data_memory (pid);
      GST_INFO ("Memory size: %d", currentMemorySize);
      BOOST_REQUIRE (currentMemorySize <= maxMemorySize);
    }
  }
}

BOOST_AUTO_TEST_CASE ( create_rtp_end_point_memory_test )
{
  MediaObject mediaManager = MediaObject();
  MediaObject mo = MediaObject();
  int i, maxMemorySize, currentMemorySize;

  BOOST_REQUIRE_MESSAGE (initialized, "Cannot connect to the server");
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);

  client->addHandlerAddress (0, "localhost", 2323);

  for (i = 0; i < ITERATIONS; i++) {
    client->createMediaManager (mediaManager, 0);
    client->createSdpEndPoint (mo, mediaManager, SdpEndPointType::type::RTP_END_POINT);
    client->release (mediaManager);

    if (i == 0) {
      maxMemorySize = get_data_memory (pid) + MEMORY_TOLERANCE;
      GST_INFO ("MAX memory size: %d", maxMemorySize);
    }

    if (i % 100 == 0) {
      currentMemorySize = get_data_memory (pid);
      GST_INFO ("Memory size: %d", currentMemorySize);
      BOOST_REQUIRE (currentMemorySize <= maxMemorySize);
    }
  }
}

BOOST_AUTO_TEST_CASE ( create_zbar_filter_test )
{
  MediaObject mediaManager = MediaObject();
  MediaObject mo = MediaObject();
  int i, maxMemorySize, currentMemorySize;

  BOOST_REQUIRE_MESSAGE (initialized, "Cannot connect to the server");
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);

  client->addHandlerAddress (0, "localhost", 2323);

  for (i = 0; i < ITERATIONS; i++) {
    client->createMediaManager (mediaManager, 0);
    client->createFilter (mo, mediaManager, FilterType::type::ZBAR_FILTER);
    client->release (mediaManager);

    if (i == 0) {
      maxMemorySize = get_data_memory (pid) + MEMORY_TOLERANCE;
      GST_INFO ("MAX memory size: %d", maxMemorySize);
    }

    if (i % 100 == 0) {
      currentMemorySize = get_data_memory (pid);
      GST_INFO ("Memory size: %d", currentMemorySize);
      BOOST_REQUIRE (currentMemorySize <= maxMemorySize);
    }
  }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 3.7.3
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.

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 "doctest_compatibility.h"

#define private public
#include <nlohmann/json.hpp>
using nlohmann::json;
#undef private

namespace
{
// special test case to check if memory is leaked if constructor throws
template<class T>
struct bad_allocator : std::allocator<T>
{
    template<class... Args>
    void construct(T*, Args&& ...)
    {
        throw std::bad_alloc();
    }
};
}

TEST_CASE("bad_alloc")
{
    SECTION("bad_alloc")
    {
        // create JSON type using the throwing allocator
        using bad_json = nlohmann::basic_json<std::map,
              std::vector,
              std::string,
              bool,
              std::int64_t,
              std::uint64_t,
              double,
              bad_allocator>;

        // creating an object should throw
        CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&);
    }
}

namespace
{
bool next_construct_fails = false;
bool next_destroy_fails = false;
bool next_deallocate_fails = false;

template<class T>
struct my_allocator : std::allocator<T>
{
    using std::allocator<T>::allocator;

    template<class... Args>
    void construct(T* p, Args&& ... args)
    {
        if (next_construct_fails)
        {
            next_construct_fails = false;
            throw std::bad_alloc();
        }
        else
        {
            ::new (reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
        }
    }

    void deallocate(T* p, std::size_t n)
    {
        if (next_deallocate_fails)
        {
            next_deallocate_fails = false;
            throw std::bad_alloc();
        }
        else
        {
            std::allocator<T>::deallocate(p, n);
        }
    }

    void destroy(T* p)
    {
        if (next_destroy_fails)
        {
            next_destroy_fails = false;
            throw std::bad_alloc();
        }
        else
        {
            p->~T();
        }
    }

    template <class U>
    struct rebind
    {
        using other = my_allocator<U>;
    };
};

// allows deletion of raw pointer, usually hold by json_value
template<class T>
void my_allocator_clean_up(T* p)
{
    assert(p != nullptr);
    my_allocator<T> alloc;
    alloc.destroy(p);
    alloc.deallocate(p, 1);
}
}

TEST_CASE("controlled bad_alloc")
{
    // create JSON type using the throwing allocator
    using my_json = nlohmann::basic_json<std::map,
          std::vector,
          std::string,
          bool,
          std::int64_t,
          std::uint64_t,
          double,
          my_allocator>;

    SECTION("class json_value")
    {
        SECTION("json_value(value_t)")
        {
            SECTION("object")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::object;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).object));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
            SECTION("array")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::array;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).array));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
            SECTION("string")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::string;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).string));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
        }

        SECTION("json_value(const string_t&)")
        {
            next_construct_fails = false;
            my_json::string_t v("foo");
            CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(v).string));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc&);
            next_construct_fails = false;
        }
    }

    SECTION("class basic_json")
    {
        SECTION("basic_json(const CompatibleObjectType&)")
        {
            next_construct_fails = false;
            std::map<std::string, std::string> v {{"foo", "bar"}};
            CHECK_NOTHROW(my_json(v));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const CompatibleArrayType&)")
        {
            next_construct_fails = false;
            std::vector<std::string> v {"foo", "bar", "baz"};
            CHECK_NOTHROW(my_json(v));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const typename string_t::value_type*)")
        {
            next_construct_fails = false;
            CHECK_NOTHROW(my_json("foo"));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json("foo"), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const typename string_t::value_type*)")
        {
            next_construct_fails = false;
            std::string s("foo");
            CHECK_NOTHROW(my_json(s));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(s), std::bad_alloc&);
            next_construct_fails = false;
        }
    }
}

namespace
{
template<class T>
struct allocator_no_forward : std::allocator<T>
{
    using std::allocator<T>::allocator;

    template <class U>
    allocator_no_forward(allocator_no_forward<U>) {}

    template <class U>
    struct rebind {
        using other =  allocator_no_forward<U>;
    };

    template <class... Args>
    void construct(T* p, const Args&... args)
    {
        ::new (static_cast<void*>(p)) T(args...);
    }
};
}

TEST_CASE("bad my_allocator::construct")
{
    SECTION("my_allocator::construct doesn't forward")
    {
        using bad_alloc_json = nlohmann::basic_json<std::map,
                                                    std::vector,
                                                    std::string,
                                                    bool,
                                                    std::int64_t,
                                                    std::uint64_t,
                                                    double,
                                                    allocator_no_forward>;

      bad_alloc_json json;
      json["test"] = bad_alloc_json::array_t();
      json["test"].push_back("should not leak");
    }
}
<commit_msg>Fix for gcc<commit_after>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 3.7.3
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.

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 "doctest_compatibility.h"

#define private public
#include <nlohmann/json.hpp>
using nlohmann::json;
#undef private

namespace
{
// special test case to check if memory is leaked if constructor throws
template<class T>
struct bad_allocator : std::allocator<T>
{
    template<class... Args>
    void construct(T*, Args&& ...)
    {
        throw std::bad_alloc();
    }
};
}

TEST_CASE("bad_alloc")
{
    SECTION("bad_alloc")
    {
        // create JSON type using the throwing allocator
        using bad_json = nlohmann::basic_json<std::map,
              std::vector,
              std::string,
              bool,
              std::int64_t,
              std::uint64_t,
              double,
              bad_allocator>;

        // creating an object should throw
        CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&);
    }
}

namespace
{
bool next_construct_fails = false;
bool next_destroy_fails = false;
bool next_deallocate_fails = false;

template<class T>
struct my_allocator : std::allocator<T>
{
    using std::allocator<T>::allocator;

    template<class... Args>
    void construct(T* p, Args&& ... args)
    {
        if (next_construct_fails)
        {
            next_construct_fails = false;
            throw std::bad_alloc();
        }
        else
        {
            ::new (reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
        }
    }

    void deallocate(T* p, std::size_t n)
    {
        if (next_deallocate_fails)
        {
            next_deallocate_fails = false;
            throw std::bad_alloc();
        }
        else
        {
            std::allocator<T>::deallocate(p, n);
        }
    }

    void destroy(T* p)
    {
        if (next_destroy_fails)
        {
            next_destroy_fails = false;
            throw std::bad_alloc();
        }
        else
        {
            p->~T();
        }
    }

    template <class U>
    struct rebind
    {
        using other = my_allocator<U>;
    };
};

// allows deletion of raw pointer, usually hold by json_value
template<class T>
void my_allocator_clean_up(T* p)
{
    assert(p != nullptr);
    my_allocator<T> alloc;
    alloc.destroy(p);
    alloc.deallocate(p, 1);
}
}

TEST_CASE("controlled bad_alloc")
{
    // create JSON type using the throwing allocator
    using my_json = nlohmann::basic_json<std::map,
          std::vector,
          std::string,
          bool,
          std::int64_t,
          std::uint64_t,
          double,
          my_allocator>;

    SECTION("class json_value")
    {
        SECTION("json_value(value_t)")
        {
            SECTION("object")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::object;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).object));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
            SECTION("array")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::array;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).array));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
            SECTION("string")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::string;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).string));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
        }

        SECTION("json_value(const string_t&)")
        {
            next_construct_fails = false;
            my_json::string_t v("foo");
            CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(v).string));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc&);
            next_construct_fails = false;
        }
    }

    SECTION("class basic_json")
    {
        SECTION("basic_json(const CompatibleObjectType&)")
        {
            next_construct_fails = false;
            std::map<std::string, std::string> v {{"foo", "bar"}};
            CHECK_NOTHROW(my_json(v));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const CompatibleArrayType&)")
        {
            next_construct_fails = false;
            std::vector<std::string> v {"foo", "bar", "baz"};
            CHECK_NOTHROW(my_json(v));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const typename string_t::value_type*)")
        {
            next_construct_fails = false;
            CHECK_NOTHROW(my_json("foo"));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json("foo"), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const typename string_t::value_type*)")
        {
            next_construct_fails = false;
            std::string s("foo");
            CHECK_NOTHROW(my_json(s));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(s), std::bad_alloc&);
            next_construct_fails = false;
        }
    }
}

namespace
{
template<class T>
struct allocator_no_forward : std::allocator<T>
{
    allocator_no_forward() {}
    template <class U>
    allocator_no_forward(allocator_no_forward<U>) {}

    template <class U>
    struct rebind {
        using other =  allocator_no_forward<U>;
    };

    template <class... Args>
    void construct(T* p, const Args&... args)
    {
        // force copy even if move is available
        ::new (static_cast<void*>(p)) T(args...);
    }
};
}

TEST_CASE("bad my_allocator::construct")
{
    SECTION("my_allocator::construct doesn't forward")
    {
        using bad_alloc_json = nlohmann::basic_json<std::map,
                                                    std::vector,
                                                    std::string,
                                                    bool,
                                                    std::int64_t,
                                                    std::uint64_t,
                                                    double,
                                                    allocator_no_forward>;

      bad_alloc_json json;
      json["test"] = bad_alloc_json::array_t();
      json["test"].push_back("should not leak");
    }
}
<|endoftext|>


<commit_before>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
http://www.etlcpp.com

Copyright(c) 2014 jwellbelove

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 <UnitTest++/UnitTest++.h>
#include <Windows.h>
#include <sstream>
#include <string>

#include "../error_handler.h"
#include "../exception.h"

bool error_received;

//*****************************************************************************
// An exception.
//*****************************************************************************
class test_exception : public etl::exception
{
public:

  test_exception(string_type file_name, numeric_type line_number)
    : exception(ETL_ERROR_TEXT("test_exception", "123"), file_name, line_number)
  {
    error_received = false;
  }
};

//*****************************************************************************
// A free error handler function.
//*****************************************************************************
void receive_error(const etl::exception& e)
{
  error_received = true;
  std::ostringstream oss;
  oss << "Error '" << e.what() << "' in " << e.file_name() << " at line " << e.line_number() << "\n";

  std::string stext = oss.str();

  WCHAR text[200];
  MultiByteToWideChar(0, 0, stext.c_str(), stext.size() + 1, text, 200);
  LPCWSTR ltext = text;

  OutputDebugString(ltext);
}

//*****************************************************************************
class test_class
{
public:

  //***************************************************************************
  // A member error handler function.
  //***************************************************************************
  void receive_error(const etl::exception& e)
  {
    error_received = true;
    std::ostringstream oss;
    oss << "Error '" << e.what() << "' in " << e.file_name() << " at line " << e.line_number() << "\n";

    std::string stext = oss.str();

    WCHAR text[200];
    MultiByteToWideChar(0, 0, stext.c_str(), stext.size() + 1, text, 200);
    LPCWSTR ltext = text;

    OutputDebugString(ltext);
  }
};

namespace
{
  SUITE(test_error_handler)
  {
    //*************************************************************************
    TEST(test_free_handler_function)
    {
      // Create the function callback object.
      etl::error_handler::free_function error_callback(receive_error);

      // Tell the error handler about it.
      etl::error_handler::set_callback(error_callback);

      // Log an error.
      etl::error_handler::error(ETL_ERROR(test_exception));

      CHECK(error_received);
    }

    //*************************************************************************
    TEST(test_member_handler_function)
    {
      // Create the class that contains the handler.
      test_class test;

      // Create the function callback object.
      etl::error_handler::member_function<test_class> error_callback(test, &test_class::receive_error);

      // Tell the error handler about it.
      etl::error_handler::set_callback(error_callback);

      // Log an error.
      etl::error_handler::error(ETL_ERROR(test_exception));

      CHECK(error_received);
    }
  };
}
<commit_msg>Added compiler #if to exclude Windows header for Linux platforms.<commit_after>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
http://www.etlcpp.com

Copyright(c) 2014 jwellbelove

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 <UnitTest++/UnitTest++.h>
#if defined(PLATFORM_WINDOWS)
#include <Windows.h>
#endif
#include <sstream>
#include <string>

#include "../error_handler.h"
#include "../exception.h"

bool error_received;

//*****************************************************************************
// An exception.
//*****************************************************************************
class test_exception : public etl::exception
{
public:

  test_exception(string_type file_name, numeric_type line_number)
    : exception(ETL_ERROR_TEXT("test_exception", "123"), file_name, line_number)
  {
    error_received = false;
  }
};

//*****************************************************************************
// A free error handler function.
//*****************************************************************************
void receive_error(const etl::exception& e)
{
  error_received = true;
  std::ostringstream oss;
  oss << "Error '" << e.what() << "' in " << e.file_name() << " at line " << e.line_number() << "\n";

#if defined(PLATFORM_WINDOWS)
  std::string stext = oss.str();

  WCHAR text[200];
  MultiByteToWideChar(0, 0, stext.c_str(), stext.size() + 1, text, 200);
  LPCWSTR ltext = text;

  OutputDebugString(ltext);
#endif
}

//*****************************************************************************
class test_class
{
public:

  //***************************************************************************
  // A member error handler function.
  //***************************************************************************
  void receive_error(const etl::exception& e)
  {
    error_received = true;
    std::ostringstream oss;
    oss << "Error '" << e.what() << "' in " << e.file_name() << " at line " << e.line_number() << "\n";

#if defined(PLATFORM_WINDOWS)
    std::string stext = oss.str();

    WCHAR text[200];
    MultiByteToWideChar(0, 0, stext.c_str(), stext.size() + 1, text, 200);
    LPCWSTR ltext = text;

    OutputDebugString(ltext);
#endif
  }
};

namespace
{
  SUITE(test_error_handler)
  {
    //*************************************************************************
    TEST(test_free_handler_function)
    {
      // Create the function callback object.
      etl::error_handler::free_function error_callback(receive_error);

      // Tell the error handler about it.
      etl::error_handler::set_callback(error_callback);

      // Log an error.
      etl::error_handler::error(ETL_ERROR(test_exception));

      CHECK(error_received);
    }

    //*************************************************************************
    TEST(test_member_handler_function)
    {
      // Create the class that contains the handler.
      test_class test;

      // Create the function callback object.
      etl::error_handler::member_function<test_class> error_callback(test, &test_class::receive_error);

      // Tell the error handler about it.
      etl::error_handler::set_callback(error_callback);

      // Log an error.
      etl::error_handler::error(ETL_ERROR(test_exception));

      CHECK(error_received);
    }
  };
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <move_basic/queued_action_server.h>
#include <queue>

class GoalQueueSuite : public ::testing::Test {
protected:
	virtual void SetUp() {
		got_goal = false;
		goal_preempted = false;
		current_goal = NULL;
		next_goal = NULL;
	}
	virtual void TearDown() {}
public:
	bool got_goal;
	bool goal_preempted;
	move_base_msgs::MoveBaseGoalConstPtr current_goal;
	move_base_msgs::MoveBaseGoalConstPtr next_goal;
	//std::queue<move_base_msgs::MoveBaseGoal> qgoals;
	ros::NodeHandle nh;
	actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction> qserv;
	actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> cli;

	GoalQueueSuite() : qserv(nh, "queue_server", boost::bind(&GoalQueueSuite::executeCallback, this, _1)),
			   cli("queue_server", true) // true -> don't need ros::spin(), required separate thread
	{
		qserv.start();
	}

	~GoalQueueSuite() {
		qserv.shutdown();
	}

	void executeCallback(const move_base_msgs::MoveBaseGoalConstPtr &msg){
		got_goal = true;
		if (current_goal == NULL) current_goal = msg;
		else if (next_goal == NULL) next_goal = msg;
		else {
			qserv.setPreempted();
			goal_preempted = true; //needed?
		}
		// TODO: Queueing behaviour
		//if (qgoals.size() > 2) { // start index?
		//	qgoals.push(*current_goal);
		//}
	}
};

TEST_F(GoalQueueSuite, establishDuplex) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;
	cli.sendGoal(goal);

	ros::spinOnce();
	ros::Duration(1.0).sleep();

	ASSERT_TRUE(got_goal);
	ASSERT_EQ(3.0, current_goal->target_pose.pose.position.x);

	// ROS API
}

TEST_F(GoalQueueSuite, queueAdding) { // probably now I should be sending to goalCallback
	/*
	- if another goal is received add it to the queue
	- if the queue full, set the current goal as preempted
	- start executing the next goal in queue (the one after the preempted)
	-
	*/

	//ASSERT_TRUE(qserv.isPreemptRequested());
}

TEST_F(GoalQueueSuite, goalPreempting) {
	/*
	- if a cancel request is received for the current goal, set it as preempted
	- if there another goal, start executing it
	- if no goal, stop
	*/
}

TEST_F(GoalQueueSuite, goalCancelling) {
	/*
	- if a cancel request on the "next_goal" received, remove it from the queue and set it as cancelled
	*/
}

// Two more TEST_F missing and a pitfall

int main(int argc, char **argv) {
    ros::init(argc, argv, "goal_queueing_test");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>Flags setup.<commit_after>#include <gtest/gtest.h>
#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <move_basic/queued_action_server.h>
#include <queue>

class GoalQueueSuite : public ::testing::Test {
protected:
	virtual void SetUp() {}
	virtual void TearDown() {}

	//SHARED POINTER

	bool got_goal;
	bool goal_preempted;
	move_base_msgs::MoveBaseGoalConstPtr current_goal;
	move_base_msgs::MoveBaseGoalConstPtr next_goal;
	ros::NodeHandle nh;
	actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction> qserv;
	actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> cli;

	// TODO: Sharing between objects? (Isolation!)
	GoalQueueSuite() : got_goal(false),
			   goal_preempted(false),
			   current_goal(nullptr),
			   next_goal(nullptr),
			   qserv(nh, "queue_server", boost::bind(&GoalQueueSuite::executeCallback, this, _1)),
			   cli("queue_server", true) // true -> don't need ros::spin(), required separate thread
	{
		qserv.start();
	}
	// ADD GOALCALLBACK

	~GoalQueueSuite() {
		qserv.shutdown();
	}

	// TODO: Making sure it gets called at the right time (flags!)
	void executeCallback(const move_base_msgs::MoveBaseGoalConstPtr &msg){
		got_goal = true;
		if (current_goal == nullptr) current_goal = msg;
		else if (next_goal == nullptr) next_goal = msg;
		else {
			current_goal = next_goal;
			goal_preempted = true;
			next_goal = msg;
		}
	}
};

TEST_F(GoalQueueSuite, establishDuplex) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;
	cli.sendGoal(goal);

	ros::spinOnce();
	ros::Duration(1.0).sleep(); // TODO: Make this disappear

	ASSERT_TRUE(got_goal);
	ASSERT_EQ(3.0, current_goal->target_pose.pose.position.x);
}

TEST_F(GoalQueueSuite, queueAdding) { // Probably now I should be sending to goalCallback?
	/*
	- if another goal is received add it to the queue
	- if the queue full, set the current goal as preempted
	- start executing the next goal in queue (the one after the preempted)
	*/

	//ASSERT_TRUE(qserv.isPreemptRequested());
}

TEST_F(GoalQueueSuite, goalPreempting) {
	/*
	- if a cancel request is received for the current goal, set it as preempted
	- if there another goal, start executing it
	- if no goal, stop
	*/
}

TEST_F(GoalQueueSuite, goalCancelling) {
	/*
	- if a cancel request on the "next_goal" received, remove it from the queue and set it as cancelled
	*/
}

// Two more TEST_F missing and a pitfall

int main(int argc, char **argv) {
    ros::init(argc, argv, "goal_queueing_test");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#include <memory>

#include <archive.h>
#include <archive_entry.h>

#include <llvm/Support/system_error.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Object/ObjectFile.h>
#include <llvm/Object/Binary.h>

#include "main.h"

Package::Object::Object(const std::string &filepath)
: path(filepath)
{
}

Package::Package(const std::string& path)
{
	error = false;

	struct archive *tar = archive_read_new();
	archive_read_support_filter_all(tar);
	archive_read_support_format_all(tar);

	struct archive_entry *entry;
	if (ARCHIVE_OK != archive_read_open_filename(tar, path.c_str(), 10240)) {
		error = true;
		return;
	}

	while (ARCHIVE_OK == archive_read_next_header(tar, &entry)) {
		//log(Log, "-> %s\n", archive_entry_pathname(entry));

		if (!add_entry(tar, entry))
			break;
	}

	archive_read_free(tar);
}

Package::Package()
{
	error = false;
}

bool
Package::care_about(struct archive_entry *entry) const
{
	mode_t mode = archive_entry_mode(entry);

	if (AE_IFLNK == (mode & AE_IFLNK)) {
		// ignoring symlinks for now
		return false;
	}

	if (AE_IFREG != (mode & AE_IFREG)) {
		// not a regular file
		return false;
	}

	if (!archive_entry_size_is_set(entry)) {
		// ignore files which have no size...
		return false;
	}

	return true;
}

bool
Package::add_entry(struct archive *tar, struct archive_entry *entry)
{
	std::string filename(archive_entry_pathname(entry));
	bool isinfo = filename == ".PKGINFO";

	// for now we only care about files named lib.*\.so(\.|$)
	if (!isinfo && !care_about(entry))
	{
		log(Debug, "skip: %s\n", filename.c_str());
		archive_read_data_skip(tar);
		return true;
	}

	// Check the size
	size_t size = archive_entry_size(entry);
	if (!size) {
		log(Error, "invalid size: %lu for file %s\n",
		    (unsigned long)size,
		    filename.c_str());
		return false;
	}

	if (isinfo)
		return read_info(tar, size);

	return read_object(tar, filename, size);
}

bool
Package::read_info(struct archive *tar, size_t size)
{
	std::unique_ptr<char> data(new char[size]);
	ssize_t rc = archive_read_data(tar, data.get(), size);
	if ((size_t)rc != size) {
		log(Error, "failed to read .PKGINFO");
		return false;
	}

	std::string str(data.get());
	size_t pos = str.find("pkgname = ");
	if (pos == std::string::npos) {
		log(Error, "missing pkgname entry in .PKGINFO");
		return false;
	}

	if (pos != 0 && data.get()[pos-1] != '\n') {
		log(Error, "corrupted .PKGINFO");
		return false;
	}

	this->name = str.substr(pos + 10, str.find_first_of(" \n\r\t", pos+10) - pos - 10);
	return true;
}

bool
Package::read_object(struct archive *tar, const std::string &filename, size_t size)
{
	std::shared_ptr<Object> binobj(new Object(filename));

	// Read into an LLVM MemoryBuffer
	std::unique_ptr<llvm::MemoryBuffer> buffer(llvm::MemoryBuffer::getNewUninitMemBuffer(size));
	char *data = const_cast<char*>(buffer->getBufferStart());

	ssize_t rc = archive_read_data(tar, data, size);
	if (rc < 0) {
		log(Error, "failed to read from archive stream\n");
		return false;
	}

	// Create an ELF Object
	// in llvm memorybuffers are moved, create a new one:
	llvm::MemoryBuffer *bufref = llvm::MemoryBuffer::getMemBuffer(buffer->getBuffer(), "", false);

	llvm::OwningPtr<llvm::object::Binary> binary;
	llvm::error_code ec = llvm::object::createBinary(bufref, binary);
	if (ec) {
		log(Debug, "nope: %s\n", filename.c_str());
		return true;
	}
	if (!binary->isObject()) {
		log(Debug, "not an object: %s\n", filename.c_str());
		return true;
	}
	if (!binary->isELF()) {
		// for now...
		log(Debug, "not an ELF object: %s\n", filename.c_str());
		return true;
	}

	std::unique_ptr<llvm::object::ObjectFile> obj(llvm::object::ObjectFile::createELFObjectFile(buffer.release()));
	log(Debug, "ELF: %s\n", filename.c_str());

	llvm::StringRef path;
	for (auto need = obj->begin_libraries_needed();
	     !ec && need != obj->end_libraries_needed();
	     need.increment(ec) )
	{
		ec = need->getPath(path);
		if (ec) {
			log(Error, "error reading library ref\n");
			return false;
		}
		binobj->need.push_back(path);
	}

	objects.push_back(binobj);

	return true;
}

void
Package::show_needed()
{
	const char *name = this->name.c_str();
	for (auto &obj : objects) {
		const char *objname = obj->path.c_str();
		for (auto &need : obj->need) {
			printf("%s: %s NEEDS %s\n", name, objname, need.c_str());
		}
	}
}
<commit_msg>empty files are not a bad thing...<commit_after>#include <memory>

#include <archive.h>
#include <archive_entry.h>

#include <llvm/Support/system_error.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Object/ObjectFile.h>
#include <llvm/Object/Binary.h>

#include "main.h"

Package::Object::Object(const std::string &filepath)
: path(filepath)
{
}

Package::Package(const std::string& path)
{
	error = false;

	struct archive *tar = archive_read_new();
	archive_read_support_filter_all(tar);
	archive_read_support_format_all(tar);

	struct archive_entry *entry;
	if (ARCHIVE_OK != archive_read_open_filename(tar, path.c_str(), 10240)) {
		error = true;
		return;
	}

	while (ARCHIVE_OK == archive_read_next_header(tar, &entry)) {
		//log(Log, "-> %s\n", archive_entry_pathname(entry));

		if (!add_entry(tar, entry))
			break;
	}

	archive_read_free(tar);
}

Package::Package()
{
	error = false;
}

bool
Package::care_about(struct archive_entry *entry) const
{
	mode_t mode = archive_entry_mode(entry);

	if (AE_IFLNK == (mode & AE_IFLNK)) {
		// ignoring symlinks for now
		return false;
	}

	if (AE_IFREG != (mode & AE_IFREG)) {
		// not a regular file
		return false;
	}

	if (!archive_entry_size_is_set(entry)) {
		// ignore files which have no size...
		return false;
	}

	return true;
}

bool
Package::add_entry(struct archive *tar, struct archive_entry *entry)
{
	std::string filename(archive_entry_pathname(entry));
	bool isinfo = filename == ".PKGINFO";

	// for now we only care about files named lib.*\.so(\.|$)
	if (!isinfo && !care_about(entry))
	{
		log(Debug, "skip: %s\n", filename.c_str());
		archive_read_data_skip(tar);
		return true;
	}

	// Check the size
	size_t size = archive_entry_size(entry);
	if (!size) {
#if 0
		log(Error, "invalid size: %lu for file %s\n",
		    (unsigned long)size,
		    filename.c_str());
		return false;
#else
		return true;
#endif
	}

	if (isinfo)
		return read_info(tar, size);

	return read_object(tar, filename, size);
}

bool
Package::read_info(struct archive *tar, size_t size)
{
	std::unique_ptr<char> data(new char[size]);
	ssize_t rc = archive_read_data(tar, data.get(), size);
	if ((size_t)rc != size) {
		log(Error, "failed to read .PKGINFO");
		return false;
	}

	std::string str(data.get());
	size_t pos = str.find("pkgname = ");
	if (pos == std::string::npos) {
		log(Error, "missing pkgname entry in .PKGINFO");
		return false;
	}

	if (pos != 0 && data.get()[pos-1] != '\n') {
		log(Error, "corrupted .PKGINFO");
		return false;
	}

	this->name = str.substr(pos + 10, str.find_first_of(" \n\r\t", pos+10) - pos - 10);
	return true;
}

bool
Package::read_object(struct archive *tar, const std::string &filename, size_t size)
{
	std::shared_ptr<Object> binobj(new Object(filename));

	// Read into an LLVM MemoryBuffer
	std::unique_ptr<llvm::MemoryBuffer> buffer(llvm::MemoryBuffer::getNewUninitMemBuffer(size));
	char *data = const_cast<char*>(buffer->getBufferStart());

	ssize_t rc = archive_read_data(tar, data, size);
	if (rc < 0) {
		log(Error, "failed to read from archive stream\n");
		return false;
	}

	// Create an ELF Object
	// in llvm memorybuffers are moved, create a new one:
	llvm::MemoryBuffer *bufref = llvm::MemoryBuffer::getMemBuffer(buffer->getBuffer(), "", false);

	llvm::OwningPtr<llvm::object::Binary> binary;
	llvm::error_code ec = llvm::object::createBinary(bufref, binary);
	if (ec) {
		log(Debug, "nope: %s\n", filename.c_str());
		return true;
	}
	if (!binary->isObject()) {
		log(Debug, "not an object: %s\n", filename.c_str());
		return true;
	}
	if (!binary->isELF()) {
		// for now...
		log(Debug, "not an ELF object: %s\n", filename.c_str());
		return true;
	}

	std::unique_ptr<llvm::object::ObjectFile> obj(llvm::object::ObjectFile::createELFObjectFile(buffer.release()));
	log(Debug, "ELF: %s\n", filename.c_str());

	llvm::StringRef path;
	for (auto need = obj->begin_libraries_needed();
	     !ec && need != obj->end_libraries_needed();
	     need.increment(ec) )
	{
		ec = need->getPath(path);
		if (ec) {
			log(Error, "error reading library ref\n");
			return false;
		}
		binobj->need.push_back(path);
	}

	objects.push_back(binobj);

	return true;
}

void
Package::show_needed()
{
	const char *name = this->name.c_str();
	for (auto &obj : objects) {
		const char *objname = obj->path.c_str();
		for (auto &need : obj->need) {
			printf("%s: %s NEEDS %s\n", name, objname, need.c_str());
		}
	}
}
<|endoftext|>