<commit_before>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "../tasking_system_handle.h"

// tasking system internals
#if defined(OSPRAY_TASKING_TBB)
# include <tbb/task_arena.h>
# include <tbb/task_scheduler_init.h>
#elif defined(OSPRAY_TASKING_CILK)
# include <cilk/cilk_api.h>
#elif defined(OSPRAY_TASKING_OMP)
# include <omp.h>
#elif defined(OSPRAY_TASKING_INTERNAL)
# include "TaskSys.h"
#endif

#include <thread>

#include "../../intrinsics.h"
#include "../../common.h"

namespace ospcommon {
  namespace tasking {

    struct tasking_system_handle
    {
      tasking_system_handle(int numThreads) :
        numThreads(numThreads)
#if defined(OSPRAY_TASKING_TBB)
        , tbb_init(numThreads)
#endif
      {
#if defined(OSPRAY_TASKING_CILK)
        __cilkrts_set_param("nworkers", std::to_string(numThreads).c_str());
#elif defined(OSPRAY_TASKING_OMP)
         if (numThreads > 0) omp_set_num_threads(numThreads);
#elif defined(OSPRAY_TASKING_INTERNAL)
         detail::initTaskSystemInternal(numThreads < 0 ? -1 : numThreads);
#endif
      }

      int num_threads()
      {
#if defined(OSPRAY_TASKING_TBB)
#  if TBB_INTERFACE_VERSION >= 9100
        return tbb::this_task_arena::max_concurrency();
#  else
        return tbb::task_scheduler_init::default_num_threads();
#  endif
#elif defined(OSPRAY_TASKING_CILK)
        return numThreads >= 0 ? numThreads : std::thread::hardware_concurrency();
#elif defined(OSPRAY_TASKING_OMP)
        int threads = 0;
        #pragma omp parallel
        {
          threads = omp_get_num_threads();
        }
        return threads;
#elif defined(OSPRAY_TASKING_INTERNAL)
        return detail::numThreadsTaskSystemInternal();
#endif
      }

      int numThreads {-1};
#if defined(OSPRAY_TASKING_TBB)
      tbb::task_scheduler_init tbb_init;
#endif
    };

    static std::unique_ptr<tasking_system_handle> g_tasking_handle;

    void initTaskingSystem(int numThreads)
    {
      _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
      _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);

#if defined(OSPRAY_TASKING_TBB)
      if (!g_tasking_handle.get())
        g_tasking_handle = make_unique<tasking_system_handle>(numThreads);
      else {
        g_tasking_handle->tbb_init.terminate();
        g_tasking_handle->tbb_init.initialize(numThreads);
      }
#else
      g_tasking_handle = make_unique<tasking_system_handle>(numThreads);
#endif
    }

    int numTaskingThreads()
    {
      if (!g_tasking_handle.get())
        return 0;
      else
        return g_tasking_handle->num_threads();
    }

    void deAffinitizeCores()
    {
#ifdef __linux__
      cpu_set_t validCores;
      CPU_ZERO(&validCores);
      for (int i=0;i<CPU_SETSIZE;i++)
        CPU_SET(i,&validCores);
      int rc = sched_setaffinity(getpid(),sizeof(validCores),&validCores);
      if (rc != 0) throw std::runtime_error("Error setting thread affinity!");
#endif
    }

  } // ::ospcommon::tasking
} // ::ospcommon
<commit_msg>fix for bad code path with Debug tasking system<commit_after>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "../tasking_system_handle.h"

// tasking system internals
#if defined(OSPRAY_TASKING_TBB)
# include <tbb/task_arena.h>
# include <tbb/task_scheduler_init.h>
#elif defined(OSPRAY_TASKING_CILK)
# include <cilk/cilk_api.h>
#elif defined(OSPRAY_TASKING_OMP)
# include <omp.h>
#elif defined(OSPRAY_TASKING_INTERNAL)
# include "TaskSys.h"
#endif

#include <thread>

#include "../../intrinsics.h"
#include "../../common.h"

namespace ospcommon {
  namespace tasking {

    struct tasking_system_handle
    {
      tasking_system_handle(int numThreads) :
        numThreads(numThreads)
#if defined(OSPRAY_TASKING_TBB)
        , tbb_init(numThreads)
#endif
      {
#if defined(OSPRAY_TASKING_CILK)
        __cilkrts_set_param("nworkers", std::to_string(numThreads).c_str());
#elif defined(OSPRAY_TASKING_OMP)
         if (numThreads > 0) omp_set_num_threads(numThreads);
#elif defined(OSPRAY_TASKING_INTERNAL)
         detail::initTaskSystemInternal(numThreads < 0 ? -1 : numThreads);
#endif
      }

      int num_threads()
      {
#if defined(OSPRAY_TASKING_TBB)
#  if TBB_INTERFACE_VERSION >= 9100
        return tbb::this_task_arena::max_concurrency();
#  else
        return tbb::task_scheduler_init::default_num_threads();
#  endif
#elif defined(OSPRAY_TASKING_CILK)
        return numThreads >= 0 ? numThreads : std::thread::hardware_concurrency();
#elif defined(OSPRAY_TASKING_OMP)
        int threads = 0;
        #pragma omp parallel
        {
          threads = omp_get_num_threads();
        }
        return threads;
#elif defined(OSPRAY_TASKING_INTERNAL)
        return detail::numThreadsTaskSystemInternal();
#else
        return 0;
#endif
      }

      int numThreads {-1};
#if defined(OSPRAY_TASKING_TBB)
      tbb::task_scheduler_init tbb_init;
#endif
    };

    static std::unique_ptr<tasking_system_handle> g_tasking_handle;

    void initTaskingSystem(int numThreads)
    {
      _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
      _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);

#if defined(OSPRAY_TASKING_TBB)
      if (!g_tasking_handle.get())
        g_tasking_handle = make_unique<tasking_system_handle>(numThreads);
      else {
        g_tasking_handle->tbb_init.terminate();
        g_tasking_handle->tbb_init.initialize(numThreads);
      }
#else
      g_tasking_handle = make_unique<tasking_system_handle>(numThreads);
#endif
    }

    int numTaskingThreads()
    {
      if (!g_tasking_handle.get())
        return 0;
      else
        return g_tasking_handle->num_threads();
    }

    void deAffinitizeCores()
    {
#ifdef __linux__
      cpu_set_t validCores;
      CPU_ZERO(&validCores);
      for (int i=0;i<CPU_SETSIZE;i++)
        CPU_SET(i,&validCores);
      int rc = sched_setaffinity(getpid(),sizeof(validCores),&validCores);
      if (rc != 0) throw std::runtime_error("Error setting thread affinity!");
#endif
    }

  } // ::ospcommon::tasking
} // ::ospcommon
<|endoftext|>


<commit_before>/**
 *  ClassInfo.cpp
 *
 *  Implementation for the class info
 *
 *  @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
 *  @copyright 2013 Copernica BV
 */
#include "includes.h"

/**
 *  Set up namespace
 */
namespace Php {

/**
 *  Function that is called to clean up space that is occupied by the object
 *  @param  object      The object to be deallocated
 */
static void deallocate_object(void *object TSRMLS_DC)
{
    // allocate memory for the object
    MixedObject *obj = (MixedObject *)object;

    // deallocate the cpp object
    if (obj->cpp) delete obj->cpp;

    // get rid of the object properties
	// @todo if we enable the following two lines, segmentation
	//		faults and memory corruption occurs. however, the online
	//		documentation does it like this
    //zend_hash_destroy(obj->php.properties);
    //FREE_HASHTABLE(obj->php.properties);

    // deallocate the entire object
    efree(obj);
}

/**
 *  Function that is called to create space for a cloned object
 *  @param  object      The object to be cloned
 *  @param  clone       The address that should become the clone
 */
static void clone_object(void *object, void **clone TSRMLS_DC)
{
    std::cout << "clone_object" << std::endl;

    // @todo implementation
}

/**
 *  Function that is called when an instance of the class needs to be created.
 *  This function will create the C++ class, and the PHP object
 *  @param  type        Pointer to the class
 */
static zend_object_value create_object(zend_class_entry *type TSRMLS_DC)
{
    // allocate memory for the object
    MixedObject *object = (MixedObject *)emalloc(sizeof(MixedObject));

    // find base object
    zend_class_entry *base = type;
    while (base->parent) base = base->parent;

    // retrieve the classinfo object
    _ClassInfo *info = (_ClassInfo *)base->info.user.doc_comment;

    // store the class
    object->php.ce = type;

    // the original create_object fills the initial object with the default properties,
    // we're going to do exactly the same. start with setting up a hashtable for the props
    ALLOC_HASHTABLE(object->php.properties);

    // initialize the hash table
    zend_hash_init(object->php.properties, 0, NULL, ZVAL_PTR_DTOR, 0);

    // initialize the properties
    object_properties_init(&(object->php), type);

    // the thing we're going to return
    zend_object_value result;

    // use default object handlers
    result.handlers = zend_get_std_object_handlers();

    // put the object in the storage, and assign a method for deallocating and cloning
    result.handle = zend_objects_store_put(object, NULL, deallocate_object, clone_object TSRMLS_CC);

    // finally, construct the cpp object
    object->cpp = info->construct();

    std::cout << "Allocate object" << std::endl;
    std::cout << object->cpp << " " << object << std::endl;

    // done
    return result;
}

/**
 *  Constructor
 *  @param  name
 */
_ClassInfo::_ClassInfo(const char *name) : _name(name), _entry(NULL)
{
}

/**
 *  Destructor
 */
_ClassInfo::~_ClassInfo()
{
}

/**
 *  Initialize the class
 *  @param  mixed       Optional threading ID
 */
void _ClassInfo::initialize(TSRMLS_DC)
{
    // the class entry
    zend_class_entry entry;

    // initialize the class entry
    INIT_CLASS_ENTRY_EX(entry, _name.c_str(), _name.size(), methods());

    // we need a special constructor
    entry.create_object = create_object;

    // register the class
    _entry = zend_register_internal_class(&entry TSRMLS_CC);

    // store pointer to the class in the unused doc_comment member
    _entry->info.user.doc_comment = (const char *)this;

    // initialize the entry
    initialize(_entry);
}

/**
 *  End of namespace
 */
}

<commit_msg>Merging master into ExampleUpdates Branch Merge branch 'master' of github.com:EmielBruijntjes/PHP-CPP into ExampleUpdates<commit_after>/**
 *  ClassInfo.cpp
 *
 *  Implementation for the class info
 *
 *  @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
 *  @copyright 2013 Copernica BV
 */
#include "includes.h"

/**
 *  Set up namespace
 */
namespace Php {

/**
 *  Function that is called to clean up space that is occupied by the object
 *  @param  object      The object to be deallocated
 */
static void deallocate_object(void *object TSRMLS_DC)
{
    // allocate memory for the object
    MixedObject *obj = (MixedObject *)object;

    // deallocate the cpp object
    if (obj->cpp) delete obj->cpp;

    // get rid of the object properties
	// @todo if we enable the following two lines, segmentation
	//		faults and memory corruption occurs. however, the online
	//		documentation does it like this
    //zend_hash_destroy(obj->php.properties);
    //FREE_HASHTABLE(obj->php.properties);

    // deallocate the entire object
    efree(obj);
}

/**
 *  Function that is called to create space for a cloned object
 *  @param  object      The object to be cloned
 *  @param  clone       The address that should become the clone
 */
static void clone_object(void *object, void **clone TSRMLS_DC)
{
    // @todo implementation
}

/**
 *  Function that is called when an instance of the class needs to be created.
 *  This function will create the C++ class, and the PHP object
 *  @param  type        Pointer to the class
 */
static zend_object_value create_object(zend_class_entry *type TSRMLS_DC)
{
    // allocate memory for the object
    MixedObject *object = (MixedObject *)emalloc(sizeof(MixedObject));

    // find base object
    zend_class_entry *base = type;
    while (base->parent) base = base->parent;

    // retrieve the classinfo object
    _ClassInfo *info = (_ClassInfo *)base->info.user.doc_comment;

    // store the class
    object->php.ce = type;

    // the original create_object fills the initial object with the default properties,
    // we're going to do exactly the same. start with setting up a hashtable for the props
    ALLOC_HASHTABLE(object->php.properties);

    // initialize the hash table
    zend_hash_init(object->php.properties, 0, NULL, ZVAL_PTR_DTOR, 0);

    // initialize the properties
    object_properties_init(&(object->php), type);

    // the thing we're going to return
    zend_object_value result;

    // use default object handlers
    result.handlers = zend_get_std_object_handlers();

    // put the object in the storage, and assign a method for deallocating and cloning
    result.handle = zend_objects_store_put(object, NULL, deallocate_object, clone_object TSRMLS_CC);

    // finally, construct the cpp object
    object->cpp = info->construct();

    // done
    return result;
}

/**
 *  Constructor
 *  @param  name
 */
_ClassInfo::_ClassInfo(const char *name) : _name(name), _entry(NULL)
{
}

/**
 *  Destructor
 */
_ClassInfo::~_ClassInfo()
{
}

/**
 *  Initialize the class
 *  @param  mixed       Optional threading ID
 */
void _ClassInfo::initialize(TSRMLS_DC)
{
    // the class entry
    zend_class_entry entry;

    // initialize the class entry
    INIT_CLASS_ENTRY_EX(entry, _name.c_str(), _name.size(), methods());

    // we need a special constructor
    entry.create_object = create_object;

    // register the class
    _entry = zend_register_internal_class(&entry TSRMLS_CC);

    // store pointer to the class in the unused doc_comment member
    _entry->info.user.doc_comment = (const char *)this;

    // initialize the entry
    initialize(_entry);
}

/**
 *  End of namespace
 */
}

<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "itkRegularExpressionSeriesFileNames.h"

int itkRegularExpressionSeriesFileNamesTest(int ac, char* av[])
{

  if(ac < 2)
  {
    std::cerr << "Usage: " << av[0] << " Directory\n";
    return EXIT_FAILURE;
  }

  itk::RegularExpressionSeriesFileNames::Pointer fit = itk::RegularExpressionSeriesFileNames::New();
  fit->SetDirectory(av[1]);
  fit->SetRegularExpression("[^.]*.(.*)");
  fit->SetSubMatch(1);

  std::vector<std::string> names = fit->GetFileNames();
  std::vector<std::string>::iterator nit;

// normal sort
  std::cout << "Normal Sort--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

// numeric sort
  fit->SetRegularExpression("[^0-9]*([0-9]*)");
  fit->NumericSortOn();
  fit->SetSubMatch(1);
  names = fit->GetFileNames();
  std::cout << "Numeric Sort--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

  std::cout << fit;

  // Show only those files with numbers in the names
  fit->SetRegularExpression("([0-9]+)");
  fit->NumericSortOn();
  fit->SetSubMatch(1);
  names = fit->GetFileNames();
  std::cout << "Numeric sort on only files with numbers in the names--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

  std::cout << "Vector size: " << names.size() << std::endl;

  // Show only those files with numbers in the names followed by other
  // numbers.  Sort them by the first set of numbers.
  fit->SetRegularExpression("([0-9]+)[^0-9]+([0-9]+)");
  fit->NumericSortOn();
  fit->SetSubMatch(1);
  names = fit->GetFileNames();
  std::cout << "Numeric sort on only files with numbers in the names.  Sort on the first set of numbers.--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

  // Show only those files with numbers in the names followed by other
  // numbers.  Sort them by the second set of numbers.
  fit->SetRegularExpression("([0-9]+)[^0-9]+([0-9]+)");
  fit->NumericSortOn();
  fit->SetSubMatch(2);
  names = fit->GetFileNames();
  std::cout << "Numeric sort on only files with numbers in the names.  Sort on the second set of numbers.--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

  std::cout << "Vector size: " << names.size() << std::endl;

  std::cout << "Directory: " << fit->GetDirectory() << std::endl;
  std::cout << "RegularExpression: " << fit->GetRegularExpression() << std::endl;
  std::cout << "SubMatch: " << fit->GetSubMatch() << std::endl;

  return EXIT_SUCCESS;

}
<commit_msg>BUG: Remove error prone test case<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "itkRegularExpressionSeriesFileNames.h"

int itkRegularExpressionSeriesFileNamesTest(int ac, char* av[])
{

  if(ac < 2)
  {
    std::cerr << "Usage: " << av[0] << " Directory\n";
    return EXIT_FAILURE;
  }

  itk::RegularExpressionSeriesFileNames::Pointer fit = itk::RegularExpressionSeriesFileNames::New();
  fit->SetDirectory(av[1]);
  fit->SetRegularExpression("[^.]*.(.*)");
  fit->SetSubMatch(1);

  std::vector<std::string> names = fit->GetFileNames();
  std::vector<std::string>::iterator nit;

// normal sort
  std::cout << "Normal Sort--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

  // Show only those files with numbers in the names
  fit->SetRegularExpression("([0-9]+)");
  fit->NumericSortOn();
  fit->SetSubMatch(1);
  names = fit->GetFileNames();
  std::cout << "Numeric sort on only files with numbers in the names--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

  std::cout << "Vector size: " << names.size() << std::endl;

  // Show only those files with numbers in the names followed by other
  // numbers.  Sort them by the first set of numbers.
  fit->SetRegularExpression("([0-9]+)[^0-9]+([0-9]+)");
  fit->NumericSortOn();
  fit->SetSubMatch(1);
  names = fit->GetFileNames();
  std::cout << "Numeric sort on only files with numbers in the names.  Sort on the first set of numbers.--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

  // Show only those files with numbers in the names followed by other
  // numbers.  Sort them by the second set of numbers.
  fit->SetRegularExpression("([0-9]+)[^0-9]+([0-9]+)");
  fit->NumericSortOn();
  fit->SetSubMatch(2);
  names = fit->GetFileNames();
  std::cout << "Numeric sort on only files with numbers in the names.  Sort on the second set of numbers.--------" << std::endl;
  for (nit = names.begin();
       nit != names.end();
       ++nit)
    {
    std::cout << "File: " << (*nit).c_str() << std::endl;
    }

  std::cout << "Vector size: " << names.size() << std::endl;

  std::cout << "Directory: " << fit->GetDirectory() << std::endl;
  std::cout << "RegularExpression: " << fit->GetRegularExpression() << std::endl;
  std::cout << "SubMatch: " << fit->GetSubMatch() << std::endl;

  return EXIT_SUCCESS;

}
<|endoftext|>


<commit_before>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include <cstring>
#include "WaveLoader.hpp"
#include "Bundle.hpp"
#include "../audio/PcmClip.hpp"
#include "../core/Engine.hpp"

namespace
{
    constexpr std::uint16_t WAVE_FORMAT_PCM = 1;
    constexpr std::uint16_t WAVE_FORMAT_IEEE_FLOAT = 3;
}

namespace ouzel::assets
{
    WaveLoader::WaveLoader(Cache& initCache):
        Loader(initCache, Type::sound)
    {
    }

    bool WaveLoader::loadAsset(Bundle& bundle,
                               const std::string& name,
                               const std::vector<std::byte>& data,
                               bool)
    {
        try
        {
            std::uint32_t channels = 0;
            std::uint32_t sampleRate = 0;

            const std::size_t formatOffset = 0;

            if (data.size() < 12) // RIFF + size + WAVE
                throw std::runtime_error("Failed to load sound file, file too small");

            if (static_cast<char>(data[formatOffset + 0]) != 'R' ||
                static_cast<char>(data[formatOffset + 1]) != 'I' ||
                static_cast<char>(data[formatOffset + 2]) != 'F' ||
                static_cast<char>(data[formatOffset + 3]) != 'F')
                throw std::runtime_error("Failed to load sound file, not a RIFF format");

            const std::size_t lengthOffset = formatOffset + 4;

            const auto length = static_cast<std::uint32_t>(data[lengthOffset + 0]) |
                static_cast<std::uint32_t>(data[lengthOffset + 1] << 8) |
                static_cast<std::uint32_t>(data[lengthOffset + 2] << 16) |
                static_cast<std::uint32_t>(data[lengthOffset + 3] << 24);

            const std::size_t typeOffset = lengthOffset + 4;

            if (data.size() < typeOffset + length)
                throw std::runtime_error("Failed to load sound file, size mismatch");

            if (length < 4 ||
                static_cast<char>(data[typeOffset + 0]) != 'W' ||
                static_cast<char>(data[typeOffset + 1]) != 'A' ||
                static_cast<char>(data[typeOffset + 2]) != 'V' ||
                static_cast<char>(data[typeOffset + 3]) != 'E')
                throw std::runtime_error("Failed to load sound file, not a WAVE file");

            std::uint16_t bitsPerSample = 0;
            std::uint16_t formatTag = 0;
            std::vector<std::byte> soundData;

            for (std::size_t offset = typeOffset + 4; offset < data.size();)
            {
                if (data.size() < offset + 8)
                    throw std::runtime_error("Failed to load sound file, not enough data to read chunk");

                const std::byte chunkHeader[4] = {
                    data[offset + 0],
                    data[offset + 1],
                    data[offset + 2],
                    data[offset + 3]
                };

                offset += 4;

                const auto chunkSize = static_cast<std::uint32_t>(data[offset + 0]) |
                    (static_cast<std::uint32_t>(data[offset + 1]) << 8) |
                    (static_cast<std::uint32_t>(data[offset + 2]) << 16) |
                    (static_cast<std::uint32_t>(data[offset + 3]) << 24);

                offset += 4;

                if (data.size() < offset + chunkSize)
                    throw std::runtime_error("Failed to load sound file, not enough data to read chunk");

                if (static_cast<char>(chunkHeader[0]) == 'f' &&
                    static_cast<char>(chunkHeader[1]) == 'm' &&
                    static_cast<char>(chunkHeader[2]) == 't' &&
                    static_cast<char>(chunkHeader[3]) == ' ')
                {
                    if (chunkSize < 16)
                        throw std::runtime_error("Failed to load sound file, not enough data to read chunk");

                    const std::size_t formatTagOffset = offset;

                    formatTag = static_cast<std::uint16_t>(static_cast<std::uint32_t>(data[formatTagOffset + 0]) |
                                                           (static_cast<std::uint32_t>(data[formatTagOffset + 1]) << 8));

                    if (formatTag != WAVE_FORMAT_PCM && formatTag != WAVE_FORMAT_IEEE_FLOAT)
                        throw std::runtime_error("Failed to load sound file, unsupported format");

                    const std::size_t channelsOffset = formatTagOffset + 2;
                    channels = static_cast<std::uint32_t>(data[channelsOffset + 0]) |
                        (static_cast<std::uint32_t>(data[channelsOffset + 1]) << 8);

                    if (!channels)
                        throw std::runtime_error("Failed to load sound file, invalid channel count");

                    const std::size_t sampleRateOffset = channelsOffset + 2;
                    sampleRate = static_cast<std::uint32_t>(data[sampleRateOffset + 0]) |
                        (static_cast<std::uint32_t>(data[sampleRateOffset + 1]) << 8) |
                        (static_cast<std::uint32_t>(data[sampleRateOffset + 2]) << 16) |
                        (static_cast<std::uint32_t>(data[sampleRateOffset + 3]) << 24);

                    if (!sampleRate)
                        throw std::runtime_error("Failed to load sound file, invalid sample rate");

                    const std::size_t byteRateOffset = sampleRateOffset + 4;
                    const std::size_t blockAlignOffset = byteRateOffset + 4;
                    const std::size_t bitsPerSampleOffset = blockAlignOffset + 2;
                    bitsPerSample = static_cast<std::uint16_t>(static_cast<std::uint32_t>(data[bitsPerSampleOffset + 0]) |
                                                               static_cast<std::uint32_t>(data[bitsPerSampleOffset + 1] << 8));

                    if (bitsPerSample != 8 && bitsPerSample != 16 &&
                        bitsPerSample != 24 && bitsPerSample != 32)
                        throw std::runtime_error("Failed to load sound file, unsupported bit depth");
                }
                else if (static_cast<char>(chunkHeader[0]) == 'd' &&
                         static_cast<char>(chunkHeader[1]) == 'a' &&
                         static_cast<char>(chunkHeader[2]) == 't' &&
                         static_cast<char>(chunkHeader[3]) == 'a')
                    soundData.assign(data.begin() + static_cast<int>(offset), data.begin() + static_cast<int>(offset + chunkSize));

                // padding
                offset += ((chunkSize + 1) & 0xFFFFFFFE);
            }

            if (!formatTag)
                throw std::runtime_error("Failed to load sound file, failed to find a format chunk");

            if (data.empty())
                throw std::runtime_error("Failed to load sound file, failed to find a data chunk");

            const auto sampleCount = static_cast<std::uint32_t>(soundData.size() / (bitsPerSample / 8));
            const auto frames = sampleCount / channels;
            std::vector<float> samples(sampleCount);

            if (formatTag == WAVE_FORMAT_PCM)
            {
                switch (bitsPerSample)
                {
                    case 8:
                    {
                        for (std::uint32_t channel = 0; channel < channels; ++channel)
                        {
                            float* outputChannel = &samples[channel * frames];

                            for (std::uint32_t frame = 0; frame < frames; ++frame)
                            {
                                const auto* sourceData = &soundData[frame * channels + channel];
                                const auto value = static_cast<std::uint8_t>(sourceData[0]);
                                outputChannel[frame] = 2.0F * value / 255.0F - 1.0F;
                            }
                        }
                        break;
                    }
                    case 16:
                    {
                        for (std::uint32_t channel = 0; channel < channels; ++channel)
                        {
                            float* outputChannel = &samples[channel * frames];

                            for (std::uint32_t frame = 0; frame < frames; ++frame)
                            {
                                const auto* sourceData = &soundData[(frame * channels + channel) * 2];
                                const auto value = static_cast<std::int32_t>(sourceData[0]) |
                                    static_cast<std::int32_t>(sourceData[1] << 8);
                                outputChannel[frame] = static_cast<float>(value) / 32767.0F;
                            }
                        }
                        break;
                    }
                    case 24:
                    {
                        for (std::uint32_t channel = 0; channel < channels; ++channel)
                        {
                            float* outputChannel = &samples[channel * frames];

                            for (std::uint32_t frame = 0; frame < frames; ++frame)
                            {
                                const auto* sourceData = &soundData[(frame * channels + channel) * 3];
                                const auto value = static_cast<std::int32_t>(sourceData[0] << 8) |
                                    static_cast<std::int32_t>(sourceData[1] << 16) |
                                    static_cast<std::int32_t>(sourceData[2] << 24);
                                outputChannel[frame] = static_cast<float>(value / 2147483648.0);
                            }
                        }
                        break;
                    }
                    case 32:
                    {
                        for (std::uint32_t channel = 0; channel < channels; ++channel)
                        {
                            float* outputChannel = &samples[channel * frames];

                            for (std::uint32_t frame = 0; frame < frames; ++frame)
                            {
                                const auto* sourceData = &soundData[(frame * channels + channel) * 4];
                                const auto value = static_cast<std::int32_t>(sourceData[0]) |
                                    static_cast<std::int32_t>(sourceData[1] << 8) |
                                    static_cast<std::int32_t>(sourceData[2] << 16) |
                                    static_cast<std::int32_t>(sourceData[3] << 24);
                                outputChannel[frame] = static_cast<float>(value / 2147483648.0);
                            }
                        }
                        break;
                    }
                    default:
                        throw std::runtime_error("Failed to load sound file, unsupported bit depth");
                }
            }
            else if (formatTag == WAVE_FORMAT_IEEE_FLOAT)
            {
                if (bitsPerSample == 32)
                {
                    for (std::uint32_t channel = 0; channel < channels; ++channel)
                    {
                        float* outputChannel = &samples[channel * frames];

                        for (std::uint32_t frame = 0; frame < frames; ++frame)
                        {
                            const auto* sourceData = &soundData[(frame * channels + channel) * 4];
                            std::memcpy(&outputChannel[frame], sourceData, sizeof(float));
                        }
                    }
                }
                else
                    throw std::runtime_error("Failed to load sound file, unsupported bit depth");
            }

            auto sound = std::make_unique<audio::PcmClip>(*engine->getAudio(), channels, sampleRate, samples);
            bundle.setSound(name, std::move(sound));
        }
        catch (const std::exception&)
        {
            return false;
        }

        return true;
    }
}
<commit_msg>Fix the wav parser<commit_after>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include <cstring>
#include "WaveLoader.hpp"
#include "Bundle.hpp"
#include "../audio/PcmClip.hpp"
#include "../core/Engine.hpp"

namespace
{
    constexpr std::uint16_t WAVE_FORMAT_PCM = 1;
    constexpr std::uint16_t WAVE_FORMAT_IEEE_FLOAT = 3;
}

namespace ouzel::assets
{
    WaveLoader::WaveLoader(Cache& initCache):
        Loader(initCache, Type::sound)
    {
    }

    bool WaveLoader::loadAsset(Bundle& bundle,
                               const std::string& name,
                               const std::vector<std::byte>& data,
                               bool)
    {
        try
        {
            std::uint32_t channels = 0;
            std::uint32_t sampleRate = 0;

            const std::size_t formatOffset = 0;

            if (data.size() < 12) // RIFF + size + WAVE
                throw std::runtime_error("Failed to load sound file, file too small");

            if (static_cast<char>(data[formatOffset + 0]) != 'R' ||
                static_cast<char>(data[formatOffset + 1]) != 'I' ||
                static_cast<char>(data[formatOffset + 2]) != 'F' ||
                static_cast<char>(data[formatOffset + 3]) != 'F')
                throw std::runtime_error("Failed to load sound file, not a RIFF format");

            const std::size_t lengthOffset = formatOffset + 4;

            const auto length = static_cast<std::uint32_t>(data[lengthOffset + 0]) |
                (static_cast<std::uint32_t>(data[lengthOffset + 1]) << 8) |
                (static_cast<std::uint32_t>(data[lengthOffset + 2]) << 16) |
                (static_cast<std::uint32_t>(data[lengthOffset + 3]) << 24);

            const std::size_t typeOffset = lengthOffset + 4;

            if (data.size() < typeOffset + length)
                throw std::runtime_error("Failed to load sound file, size mismatch");

            if (length < 4 ||
                static_cast<char>(data[typeOffset + 0]) != 'W' ||
                static_cast<char>(data[typeOffset + 1]) != 'A' ||
                static_cast<char>(data[typeOffset + 2]) != 'V' ||
                static_cast<char>(data[typeOffset + 3]) != 'E')
                throw std::runtime_error("Failed to load sound file, not a WAVE file");

            std::uint16_t bitsPerSample = 0;
            std::uint16_t formatTag = 0;
            std::vector<std::byte> soundData;

            for (std::size_t offset = typeOffset + 4; offset < data.size();)
            {
                if (data.size() < offset + 8)
                    throw std::runtime_error("Failed to load sound file, not enough data to read chunk");

                const std::byte chunkHeader[4] = {
                    data[offset + 0],
                    data[offset + 1],
                    data[offset + 2],
                    data[offset + 3]
                };

                offset += 4;

                const auto chunkSize = static_cast<std::uint32_t>(data[offset + 0]) |
                    (static_cast<std::uint32_t>(data[offset + 1]) << 8) |
                    (static_cast<std::uint32_t>(data[offset + 2]) << 16) |
                    (static_cast<std::uint32_t>(data[offset + 3]) << 24);

                offset += 4;

                if (data.size() < offset + chunkSize)
                    throw std::runtime_error("Failed to load sound file, not enough data to read chunk");

                if (static_cast<char>(chunkHeader[0]) == 'f' &&
                    static_cast<char>(chunkHeader[1]) == 'm' &&
                    static_cast<char>(chunkHeader[2]) == 't' &&
                    static_cast<char>(chunkHeader[3]) == ' ')
                {
                    if (chunkSize < 16)
                        throw std::runtime_error("Failed to load sound file, not enough data to read chunk");

                    const std::size_t formatTagOffset = offset;

                    formatTag = static_cast<std::uint16_t>(static_cast<std::uint32_t>(data[formatTagOffset + 0]) |
                                                           (static_cast<std::uint32_t>(data[formatTagOffset + 1]) << 8));

                    if (formatTag != WAVE_FORMAT_PCM && formatTag != WAVE_FORMAT_IEEE_FLOAT)
                        throw std::runtime_error("Failed to load sound file, unsupported format");

                    const std::size_t channelsOffset = formatTagOffset + 2;
                    channels = static_cast<std::uint32_t>(data[channelsOffset + 0]) |
                        (static_cast<std::uint32_t>(data[channelsOffset + 1]) << 8);

                    if (!channels)
                        throw std::runtime_error("Failed to load sound file, invalid channel count");

                    const std::size_t sampleRateOffset = channelsOffset + 2;
                    sampleRate = static_cast<std::uint32_t>(data[sampleRateOffset + 0]) |
                        (static_cast<std::uint32_t>(data[sampleRateOffset + 1]) << 8) |
                        (static_cast<std::uint32_t>(data[sampleRateOffset + 2]) << 16) |
                        (static_cast<std::uint32_t>(data[sampleRateOffset + 3]) << 24);

                    if (!sampleRate)
                        throw std::runtime_error("Failed to load sound file, invalid sample rate");

                    const std::size_t byteRateOffset = sampleRateOffset + 4;
                    const std::size_t blockAlignOffset = byteRateOffset + 4;
                    const std::size_t bitsPerSampleOffset = blockAlignOffset + 2;
                    bitsPerSample = static_cast<std::uint16_t>(static_cast<std::uint32_t>(data[bitsPerSampleOffset + 0]) |
                                                               (static_cast<std::uint32_t>(data[bitsPerSampleOffset + 1]) << 8));

                    if (bitsPerSample != 8 && bitsPerSample != 16 &&
                        bitsPerSample != 24 && bitsPerSample != 32)
                        throw std::runtime_error("Failed to load sound file, unsupported bit depth");
                }
                else if (static_cast<char>(chunkHeader[0]) == 'd' &&
                         static_cast<char>(chunkHeader[1]) == 'a' &&
                         static_cast<char>(chunkHeader[2]) == 't' &&
                         static_cast<char>(chunkHeader[3]) == 'a')
                    soundData.assign(data.begin() + static_cast<int>(offset), data.begin() + static_cast<int>(offset + chunkSize));

                // padding
                offset += ((chunkSize + 1) & 0xFFFFFFFE);
            }

            if (!formatTag)
                throw std::runtime_error("Failed to load sound file, failed to find a format chunk");

            if (data.empty())
                throw std::runtime_error("Failed to load sound file, failed to find a data chunk");

            const auto sampleCount = static_cast<std::uint32_t>(soundData.size() / (bitsPerSample / 8));
            const auto frames = sampleCount / channels;
            std::vector<float> samples(sampleCount);

            if (formatTag == WAVE_FORMAT_PCM)
            {
                switch (bitsPerSample)
                {
                    case 8:
                    {
                        for (std::uint32_t channel = 0; channel < channels; ++channel)
                        {
                            float* outputChannel = &samples[channel * frames];

                            for (std::uint32_t frame = 0; frame < frames; ++frame)
                            {
                                const auto* sourceData = &soundData[frame * channels + channel];
                                const auto value = static_cast<std::uint8_t>(sourceData[0]);
                                outputChannel[frame] = 2.0F * value / 255.0F - 1.0F;
                            }
                        }
                        break;
                    }
                    case 16:
                    {
                        for (std::uint32_t channel = 0; channel < channels; ++channel)
                        {
                            float* outputChannel = &samples[channel * frames];

                            for (std::uint32_t frame = 0; frame < frames; ++frame)
                            {
                                const auto* sourceData = &soundData[(frame * channels + channel) * 2];
                                const auto value = static_cast<std::int32_t>(sourceData[0]) |
                                    (static_cast<std::int32_t>(sourceData[1]) << 8);
                                outputChannel[frame] = static_cast<float>(value) / 32767.0F;
                            }
                        }
                        break;
                    }
                    case 24:
                    {
                        for (std::uint32_t channel = 0; channel < channels; ++channel)
                        {
                            float* outputChannel = &samples[channel * frames];

                            for (std::uint32_t frame = 0; frame < frames; ++frame)
                            {
                                const auto* sourceData = &soundData[(frame * channels + channel) * 3];
                                const auto value = (static_cast<std::int32_t>(sourceData[0]) << 8) |
                                    (static_cast<std::int32_t>(sourceData[1]) << 16) |
                                    (static_cast<std::int32_t>(sourceData[2]) << 24);
                                outputChannel[frame] = static_cast<float>(value / 2147483648.0);
                            }
                        }
                        break;
                    }
                    case 32:
                    {
                        for (std::uint32_t channel = 0; channel < channels; ++channel)
                        {
                            float* outputChannel = &samples[channel * frames];

                            for (std::uint32_t frame = 0; frame < frames; ++frame)
                            {
                                const auto* sourceData = &soundData[(frame * channels + channel) * 4];
                                const auto value = static_cast<std::int32_t>(sourceData[0]) |
                                    (static_cast<std::int32_t>(sourceData[1]) << 8) |
                                    (static_cast<std::int32_t>(sourceData[2]) << 16) |
                                    (static_cast<std::int32_t>(sourceData[3]) << 24);
                                outputChannel[frame] = static_cast<float>(value / 2147483648.0);
                            }
                        }
                        break;
                    }
                    default:
                        throw std::runtime_error("Failed to load sound file, unsupported bit depth");
                }
            }
            else if (formatTag == WAVE_FORMAT_IEEE_FLOAT)
            {
                if (bitsPerSample == 32)
                {
                    for (std::uint32_t channel = 0; channel < channels; ++channel)
                    {
                        float* outputChannel = &samples[channel * frames];

                        for (std::uint32_t frame = 0; frame < frames; ++frame)
                        {
                            const auto* sourceData = &soundData[(frame * channels + channel) * 4];
                            std::memcpy(&outputChannel[frame], sourceData, sizeof(float));
                        }
                    }
                }
                else
                    throw std::runtime_error("Failed to load sound file, unsupported bit depth");
            }

            auto sound = std::make_unique<audio::PcmClip>(*engine->getAudio(), channels, sampleRate, samples);
            bundle.setSound(name, std::move(sound));
        }
        catch (const std::exception&)
        {
            return false;
        }

        return true;
    }
}
<|endoftext|>


<commit_before>#include "occaParser.hpp"

namespace occa {
  namespace parserNamespace {
    _qualifierInfo::_qualifierInfo() :
      qualifierCount(0),
      qualifiers(NULL) {}

    _qualifierInfo::_qualifierInfo(const _qualifierInfo &q) :
      qualifierCount(q.qualifierCount),
      qualifiers(q.qualifiers) {}

    _qualifierInfo& _qualifierInfo::operator = (const _qualifierInfo &q){
      qualifierCount = q.qualifierCount;
      qualifiers     = q.qualifiers;

      return *this;
    }

    _qualifierInfo _qualifierInfo::clone(){
      _qualifierInfo q;

      q.qualifierCount = qualifierCount;

      q.qualifiers = new std::string[qualifierCount];

      for(int i = 0; i < qualifierCount; ++i)
        q.qualifiers[i] = qualifiers[i];

      return q;
    }

    strNode* _qualifierInfo::loadFrom(statement &s,
                                      strNode *nodePos){
      strNode *nodeRoot = nodePos;

      while(nodePos &&
            s.nodeHasQualifier(nodePos)){
        ++qualifierCount;
        nodePos = nodePos->right;
      }

      if(qualifierCount){
        qualifiers = new std::string[qualifierCount];
        nodePos = nodeRoot;

        for(int i = 0; i < qualifierCount; ++i){
          qualifiers[i] = nodePos->value;
          nodePos = nodePos->right;
        }
      }

      return nodePos;
    }

    std::string _qualifierInfo::toString(){
      std::string ret;

      for(int i = 0; i < qualifierCount; ++i){
        ret += qualifiers[i];

        if((qualifiers[i][0] != '*') ||
           ( ((i + 1) < qualifierCount) &&
             (qualifiers[i + 1][0] != '*') )){

          ret += ' ';
        }
      }

      return ret;
    }

    _varInfo::_varInfo() :
      info(0),

      leftQualifiers(),
      rightQualifiers(),

      baseType(NULL),

      name(""),

      pointerCount(0),
      stackPointerCount(0),
      stackExpRoots(NULL),

      argumentCount(0),
      argumentVarInfos(NULL),

      functionNestCount(0),
      functionNests(NULL) {}

    _varInfo::_varInfo(const _varInfo &var) :
      info(var.info),

      leftQualifiers(var.leftQualifiers),
      rightQualifiers(var.rightQualifiers),

      baseType(var.baseType),

      name(var.name),

      pointerCount(var.pointerCount),
      stackPointerCount(var.stackPointerCount),
      stackExpRoots(var.stackExpRoots),

      argumentCount(var.argumentCount),
      argumentVarInfos(var.argumentVarInfos),

      functionNestCount(var.functionNestCount),
      functionNests(var.functionNests) {}

    _varInfo& _varInfo::operator = (const _varInfo &var){
      info = var.info;

      leftQualifiers  = var.leftQualifiers;
      rightQualifiers = var.rightQualifiers;

      baseType = var.baseType;

      name = var.name;

      pointerCount      = var.pointerCount;
      stackPointerCount = var.stackPointerCount;
      stackExpRoots     = var.stackExpRoots;

      argumentCount    = var.argumentCount;
      argumentVarInfos = var.argumentVarInfos;

      functionNestCount = var.functionNestCount;
      functionNests     = var.functionNests;

      return *this;
    }

    int _varInfo::variablesInStatement(strNode *nodePos){
      int argc = 0;

      while(nodePos){
        if((nodePos->value == ",") ||
           (nodePos->value == ";")){

          ++argc;
        }
        else if((nodePos->right) == NULL)
          ++argc;

        nodePos = nodePos->right;
      }

      return argc;
    }

    strNode* _varInfo::loadValueFrom(statement &s,
                                     strNode *nodePos,
                                     _varInfo *varHasType){
      nodePos = loadTypeFrom(s, nodePos, varHasType);

      info = getVarInfoFrom(s, nodePos);

      if(info & _varType::functionPointer){
        functionNestCount = getNestCountFrom(s, nodePos);
        functionNests     = new _varInfo[functionNestCount];
      }

      nodePos = loadNameFrom(s, nodePos);
      nodePos = loadArgsFrom(s, nodePos);

      if(nodePos &&
         (nodePos->value == ","))
        nodePos = nodePos->right;

      return nodePos;
    }

    strNode* _varInfo::loadTypeFrom(statement &s,
                                    strNode *nodePos,
                                    _varInfo *varHasType){
      if(varHasType == NULL){
        nodePos = leftQualifiers.loadFrom(s, nodePos);

        baseType = s.hasTypeInScope(nodePos->value);

        if(baseType)
          nodePos = nodePos->right;
      }
      else{
        leftQualifiers = varHasType->leftQualifiers;
        baseType       = varHasType->baseType;
      }

      nodePos = rightQualifiers.loadFrom(s, nodePos);

      return nodePos;
    }

    int _varInfo::getVarInfoFrom(statement &s,
                                 strNode *nodePos){
      // No name var (argument for function)
      if(nodePos == NULL)
        return _varType::var;

      strNode *nextNode = nodePos->right;

      const int nestCount = getNestCountFrom(s, nodePos);

      if(nestCount)
        return _varType::functionPointer;

      if(nextNode &&
         (nextNode->type == startParentheses))
        return _varType::function;

      return _varType::var;
    }

    int _varInfo::getNestCountFrom(statement &s,
                                   strNode *nodePos){
      int nestCount = 0;

      while(nodePos &&
            (nodePos->type == startParentheses)){

        nodePos = nodePos->down;

        if(nodePos &&
           nodePos->value == "*"){

          ++nestCount;
          nodePos = nodePos->right;
        }
      }

      return nestCount;
    }

    strNode* _varInfo::loadNameFrom(statement &s,
                                    strNode *nodePos){
      if(nodePos == NULL)
        return NULL;

      strNode *nextNode = nodePos->right;

      int nestPos = 0;

      while(nodePos &&
            (nodePos->type == startParentheses)){

        nodePos = nodePos->down;

        if(nodePos &&
           nodePos->value == "*"){

          nodePos = nodePos->right;

          if(nodePos        &&
             nodePos->right &&
             (nodePos->right->type == startParentheses)){

            functionNests[nestPos].info = _varType::function;
            functionNests[nestPos].loadArgsFrom(s, nodePos->right);
          }

          ++nestPos;
        }
      }

      if(nodePos &&
         (nodePos->type & unknownVariable)){

        name    = nodePos->value;
        nodePos = nodePos->right;

        if(nodePos == nextNode)
          nextNode = loadStackPointersFrom(s, nextNode);
        else
          nodePos = loadStackPointersFrom(s, nodePos);
      }

      return nextNode;
    }

    strNode* _varInfo::loadStackPointersFrom(statement &s,
                                             strNode *nodePos){
      strNode *nodeRoot = nodePos;

      if(nodePos &&
         (nodePos->value == "[") &&
         (nodePos->down)){

        ++stackPointerCount;
        nodePos = nodePos->right;
      }

      if(stackPointerCount){
        nodePos = nodeRoot;

        stackExpRoots = new expNode[stackPointerCount];

        for(int i = 0; i < stackPointerCount; ++i){
          stackExpRoots[i].sInfo = &s;

          if(nodePos->down){
            strNode *downNode = nodePos->down;
            strNode *lastDown = lastNode(downNode);

            // s.setExpNodeFromStrNode(stackExpRoots[i], downNode);
          }

          nodePos = nodePos->right;
        }
      }

      return nodePos;
    }

    strNode* _varInfo::loadArgsFrom(statement &s,
                                    strNode *nodePos){
      if( !(info & _varType::functionType) )
        return nodePos;

      if(nodePos == NULL){
        std::cout << "Missing arguments from function variable\n";
        throw 1;
      }

      strNode *nextNode = nodePos->right;

      if(nodePos->down){
        nodePos = nodePos->down;

        argumentCount    = variablesInStatement(nodePos);
        argumentVarInfos = new _varInfo[argumentCount];

        for(int i = 0; i < argumentCount; ++i)
          nodePos = argumentVarInfos[i].loadValueFrom(s, nodePos);
      }

      return nextNode;
    }

    std::string _varInfo::toString(const bool printType){
      std::string ret;

      if(printType){
        ret += leftQualifiers.toString();

        if(baseType)
          ret += baseType->typeName;

        if((rightQualifiers.qualifierCount) ||
           (name.size())){

          ret += ' ';
        }
      }

      ret += rightQualifiers.toString();

      for(int i = 0; i < functionNestCount; ++i)
        ret += "(*";

      ret += name;

      for(int i = 0; i < stackPointerCount; ++i){
        ret += '[';
        ret += (std::string) stackExpRoots[i];
        ret += ']';
      }

      for(int i = 0; i < functionNestCount; ++i){
        ret += ')';
        ret += functionNests[i].toString();
      }

      if(info & _varType::functionType){
        ret += '(';

        for(int i = 0; i < argumentCount; ++i)
          ret += argumentVarInfos[i].toString();

        ret += ')';
      }

      return ret;
    }

    _varInfo::operator std::string (){
      return toString();
    }

    std::ostream& operator << (std::ostream &out, _varInfo &var){
      out << var.toString();
      return out;
    }

    expNode* addNewVariables(strNode *nodePos){
      return NULL;
    }

    void test(){
      parser p;
      p.loadLanguageTypes();
      statement &s = *(p.globalScope);

      strNode *nodeRoot = p.splitAndPreprocessContent("const int *const ** const***a[2], *b, ((c)), d[3], e(int), (f), ((*g))(), (*(*h)(int))(double);");

      const int varCount = _varInfo::variablesInStatement(nodeRoot);

      if(varCount){
        _varInfo *variables = new _varInfo[varCount];

        nodeRoot = variables[0].loadValueFrom(s, nodeRoot);
        std::cout << "variables[0] = " << variables[0] << '\n';

        for(int i = 1; i < varCount; ++i){
          nodeRoot = variables[i].loadValueFrom(s, nodeRoot, &(variables[0]));
          std::cout << "variables[" << i << "] = " << variables[i] << '\n';
        }
      }

      // expNode *expRoot = addNewVariables(nodeRoot);
      // expRoot->print();

      throw 1;
    }
  };
};

int main(int argc, char **argv){
  occa::parserNamespace::test();

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/easy.c");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/test.cpp");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/openclTest.cpp");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/cudaTest.cpp");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/midg.okl");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/cleanTest.c");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/clangTest.c");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/addVectors.okl");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/PCGpart1.cl");
  //   std::cout << parsedContent << '\n';
  // }

  {
    occa::parser parser;
    std::string parsedContent = parser.parseFile("tests/lookup_kernel.okl");
    std::cout << parsedContent << '\n';
  }
}
<commit_msg>[Parser] Fixed functionPointer output<commit_after>#include "occaParser.hpp"

namespace occa {
  namespace parserNamespace {
    _qualifierInfo::_qualifierInfo() :
      qualifierCount(0),
      qualifiers(NULL) {}

    _qualifierInfo::_qualifierInfo(const _qualifierInfo &q) :
      qualifierCount(q.qualifierCount),
      qualifiers(q.qualifiers) {}

    _qualifierInfo& _qualifierInfo::operator = (const _qualifierInfo &q){
      qualifierCount = q.qualifierCount;
      qualifiers     = q.qualifiers;

      return *this;
    }

    _qualifierInfo _qualifierInfo::clone(){
      _qualifierInfo q;

      q.qualifierCount = qualifierCount;

      q.qualifiers = new std::string[qualifierCount];

      for(int i = 0; i < qualifierCount; ++i)
        q.qualifiers[i] = qualifiers[i];

      return q;
    }

    strNode* _qualifierInfo::loadFrom(statement &s,
                                      strNode *nodePos){
      strNode *nodeRoot = nodePos;

      while(nodePos &&
            s.nodeHasQualifier(nodePos)){
        ++qualifierCount;
        nodePos = nodePos->right;
      }

      if(qualifierCount){
        qualifiers = new std::string[qualifierCount];
        nodePos = nodeRoot;

        for(int i = 0; i < qualifierCount; ++i){
          qualifiers[i] = nodePos->value;
          nodePos = nodePos->right;
        }
      }

      return nodePos;
    }

    std::string _qualifierInfo::toString(){
      std::string ret;

      for(int i = 0; i < qualifierCount; ++i){
        ret += qualifiers[i];

        if((qualifiers[i][0] != '*') ||
           ( ((i + 1) < qualifierCount) &&
             (qualifiers[i + 1][0] != '*') )){

          ret += ' ';
        }
      }

      return ret;
    }

    _varInfo::_varInfo() :
      info(0),

      leftQualifiers(),
      rightQualifiers(),

      baseType(NULL),

      name(""),

      pointerCount(0),
      stackPointerCount(0),
      stackExpRoots(NULL),

      argumentCount(0),
      argumentVarInfos(NULL),

      functionNestCount(0),
      functionNests(NULL) {}

    _varInfo::_varInfo(const _varInfo &var) :
      info(var.info),

      leftQualifiers(var.leftQualifiers),
      rightQualifiers(var.rightQualifiers),

      baseType(var.baseType),

      name(var.name),

      pointerCount(var.pointerCount),
      stackPointerCount(var.stackPointerCount),
      stackExpRoots(var.stackExpRoots),

      argumentCount(var.argumentCount),
      argumentVarInfos(var.argumentVarInfos),

      functionNestCount(var.functionNestCount),
      functionNests(var.functionNests) {}

    _varInfo& _varInfo::operator = (const _varInfo &var){
      info = var.info;

      leftQualifiers  = var.leftQualifiers;
      rightQualifiers = var.rightQualifiers;

      baseType = var.baseType;

      name = var.name;

      pointerCount      = var.pointerCount;
      stackPointerCount = var.stackPointerCount;
      stackExpRoots     = var.stackExpRoots;

      argumentCount    = var.argumentCount;
      argumentVarInfos = var.argumentVarInfos;

      functionNestCount = var.functionNestCount;
      functionNests     = var.functionNests;

      return *this;
    }

    int _varInfo::variablesInStatement(strNode *nodePos){
      int argc = 0;

      while(nodePos){
        if((nodePos->value == ",") ||
           (nodePos->value == ";")){

          ++argc;
        }
        else if((nodePos->right) == NULL)
          ++argc;

        nodePos = nodePos->right;
      }

      return argc;
    }

    strNode* _varInfo::loadValueFrom(statement &s,
                                     strNode *nodePos,
                                     _varInfo *varHasType){
      nodePos = loadTypeFrom(s, nodePos, varHasType);

      info = getVarInfoFrom(s, nodePos);

      if(info & _varType::functionPointer){
        functionNestCount = getNestCountFrom(s, nodePos);
        functionNests     = new _varInfo[functionNestCount];
      }

      nodePos = loadNameFrom(s, nodePos);
      nodePos = loadArgsFrom(s, nodePos);

      if(nodePos &&
         (nodePos->value == ","))
        nodePos = nodePos->right;

      return nodePos;
    }

    strNode* _varInfo::loadTypeFrom(statement &s,
                                    strNode *nodePos,
                                    _varInfo *varHasType){
      if(varHasType == NULL){
        nodePos = leftQualifiers.loadFrom(s, nodePos);

        baseType = s.hasTypeInScope(nodePos->value);

        if(baseType)
          nodePos = nodePos->right;
      }
      else{
        leftQualifiers = varHasType->leftQualifiers;
        baseType       = varHasType->baseType;
      }

      nodePos = rightQualifiers.loadFrom(s, nodePos);

      return nodePos;
    }

    int _varInfo::getVarInfoFrom(statement &s,
                                 strNode *nodePos){
      // No name var (argument for function)
      if(nodePos == NULL)
        return _varType::var;

      strNode *nextNode = nodePos->right;

      const int nestCount = getNestCountFrom(s, nodePos);

      if(nestCount)
        return _varType::functionPointer;

      if(nextNode &&
         (nextNode->type == startParentheses))
        return _varType::function;

      return _varType::var;
    }

    int _varInfo::getNestCountFrom(statement &s,
                                   strNode *nodePos){
      int nestCount = 0;

      while(nodePos &&
            (nodePos->type == startParentheses)){

        nodePos = nodePos->down;

        if(nodePos &&
           nodePos->value == "*"){

          ++nestCount;
          nodePos = nodePos->right;
        }
      }

      return nestCount;
    }

    strNode* _varInfo::loadNameFrom(statement &s,
                                    strNode *nodePos){
      if(nodePos == NULL)
        return NULL;

      strNode *nextNode = nodePos->right;

      int nestPos = 0;

      while(nodePos &&
            (nodePos->type == startParentheses)){

        nodePos = nodePos->down;

        if(nodePos &&
           nodePos->value == "*"){

          nodePos = nodePos->right;

          if(nodePos        &&
             nodePos->right &&
             (nodePos->right->type == startParentheses)){

            functionNests[nestPos].info = _varType::function;
            functionNests[nestPos].loadArgsFrom(s, nodePos->right);
          }

          ++nestPos;
        }
      }

      if(nodePos &&
         (nodePos->type & unknownVariable)){

        name    = nodePos->value;
        nodePos = nodePos->right;

        if(nodePos == nextNode)
          nextNode = loadStackPointersFrom(s, nextNode);
        else
          nodePos = loadStackPointersFrom(s, nodePos);
      }

      return nextNode;
    }

    strNode* _varInfo::loadStackPointersFrom(statement &s,
                                             strNode *nodePos){
      strNode *nodeRoot = nodePos;

      if(nodePos &&
         (nodePos->value == "[") &&
         (nodePos->down)){

        ++stackPointerCount;
        nodePos = nodePos->right;
      }

      if(stackPointerCount){
        nodePos = nodeRoot;

        stackExpRoots = new expNode[stackPointerCount];

        for(int i = 0; i < stackPointerCount; ++i){
          stackExpRoots[i].sInfo = &s;

          if(nodePos->down){
            strNode *downNode = nodePos->down;
            strNode *lastDown = lastNode(downNode);

            // s.setExpNodeFromStrNode(stackExpRoots[i], downNode);
          }

          nodePos = nodePos->right;
        }
      }

      return nodePos;
    }

    strNode* _varInfo::loadArgsFrom(statement &s,
                                    strNode *nodePos){
      if( !(info & _varType::functionType) )
        return nodePos;

      if(nodePos == NULL){
        std::cout << "Missing arguments from function variable\n";
        throw 1;
      }

      strNode *nextNode = nodePos->right;

      if(nodePos->down){
        nodePos = nodePos->down;

        argumentCount    = variablesInStatement(nodePos);
        argumentVarInfos = new _varInfo[argumentCount];

        for(int i = 0; i < argumentCount; ++i)
          nodePos = argumentVarInfos[i].loadValueFrom(s, nodePos);
      }

      return nextNode;
    }

    std::string _varInfo::toString(const bool printType){
      std::string ret;

      if(printType){
        ret += leftQualifiers.toString();

        if(baseType)
          ret += baseType->typeName;

        if((rightQualifiers.qualifierCount) ||
           (name.size())){

          ret += ' ';
        }
      }

      ret += rightQualifiers.toString();

      for(int i = 0; i < functionNestCount; ++i)
        ret += "(*";

      ret += name;

      for(int i = 0; i < stackPointerCount; ++i){
        ret += '[';
        ret += (std::string) stackExpRoots[i];
        ret += ']';
      }

      for(int i = (functionNestCount - 1); 0 <= i; --i){
        ret += functionNests[i].toString();
        ret += ')';
      }

      if(info & _varType::functionType){
        ret += '(';

        for(int i = 0; i < argumentCount; ++i)
          ret += argumentVarInfos[i].toString();

        ret += ')';
      }

      return ret;
    }

    _varInfo::operator std::string (){
      return toString();
    }

    std::ostream& operator << (std::ostream &out, _varInfo &var){
      out << var.toString();
      return out;
    }

    expNode* addNewVariables(strNode *nodePos){
      return NULL;
    }

    void test(){
      parser p;
      p.loadLanguageTypes();
      statement &s = *(p.globalScope);

      strNode *nodeRoot = p.splitAndPreprocessContent("const int *const ** const***a[2], *b, ((c)), d[3], e(int), (f), ((*g))(), (*(*h)(int))(double), (*(*(*i)())(int))(double);");

      const int varCount = _varInfo::variablesInStatement(nodeRoot);

      if(varCount){
        _varInfo *variables = new _varInfo[varCount];

        nodeRoot = variables[0].loadValueFrom(s, nodeRoot);
        std::cout << "variables[0] = " << variables[0] << '\n';

        for(int i = 1; i < varCount; ++i){
          nodeRoot = variables[i].loadValueFrom(s, nodeRoot, &(variables[0]));
          std::cout << "variables[" << i << "] = " << variables[i] << '\n';
        }
      }

      // expNode *expRoot = addNewVariables(nodeRoot);
      // expRoot->print();

      throw 1;
    }
  };
};

int main(int argc, char **argv){
  occa::parserNamespace::test();

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/easy.c");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/test.cpp");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/openclTest.cpp");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/cudaTest.cpp");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/midg.okl");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/cleanTest.c");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/clangTest.c");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/addVectors.okl");
  //   std::cout << parsedContent << '\n';
  // }

  // {
  //   occa::parser parser;
  //   std::string parsedContent = parser.parseFile("tests/PCGpart1.cl");
  //   std::cout << parsedContent << '\n';
  // }

  {
    occa::parser parser;
    std::string parsedContent = parser.parseFile("tests/lookup_kernel.okl");
    std::cout << parsedContent << '\n';
  }
}
<|endoftext|>


<commit_before>#include "stun.h"
#include "stunmsgfact.h"

#include <QDnsLookup>
#include <QHostInfo>
#include <QDateTime>
#include <QDebug>
#include <QMutex>
#include <QWaitCondition>
#include <QEventLoop>

#include <QtEndian>

const uint16_t GOOGLE_STUN_PORT = 19302;
const uint16_t STUN_PORT = 21000;

Stun::Stun():
  udp_(),
  stunmsg_()
{}

void Stun::wantAddress(QString stunServer)
{
  // To find the IP address of qt-project.org
  QHostInfo::lookupHost(stunServer, this, SLOT(handleHostaddress(QHostInfo)));
}

void Stun::handleHostaddress(QHostInfo info)
{
  const auto addresses = info.addresses();
  QHostAddress address;
  if(addresses.size() != 0)
  {
    address = addresses.at(0);
    qDebug() <<"Found" << addresses.size() << "stun server addresses. Using:" << address.toString();
  }
  else
  {
    qDebug() << "Did not find any addresses";
    return;
  }

  udp_.bind(QHostAddress::AnyIPv4, STUN_PORT);
  QObject::connect(&udp_, SIGNAL(messageAvailable(QByteArray)), this, SLOT(processReply(QByteArray)));

  STUNMessage request_ = stunmsg_.createRequest();
  QByteArray   message_ = stunmsg_.hostToNetwork(request_);

  udp_.sendData(message_, address, GOOGLE_STUN_PORT, false);
}

bool Stun::waitForStunResponse(unsigned long timeout)
{
  QTimer timer;
  timer.setSingleShot(true);
  QEventLoop loop;

  connect(this,   &Stun::parsingDone, &loop, &QEventLoop::quit);
  connect(&timer, &QTimer::timeout,   &loop, &QEventLoop::quit);

  timer.start(timeout);
  loop.exec();

  return timer.isActive();
}

bool Stun::waitForNominationRequest(unsigned long timeout)
{
  QTimer timer;
  timer.setSingleShot(true);
  QEventLoop loop;

  connect(this,   &Stun::nominationRecv, &loop, &QEventLoop::quit);
  connect(&timer, &QTimer::timeout,   &loop, &QEventLoop::quit);

  timer.start(timeout);
  loop.exec();

  return timer.isActive();
}

bool Stun::sendBindingRequest(ICEPair *pair, bool controller)
{
  if (controller)
    qDebug() << "[controller] BINDING " << pair->local->address<< " TO PORT " << pair->local->port;
  else
    qDebug() << "[controllee] BINDING " << pair->local->address << " TO PORT " << pair->local->port;

  if (!udp_.bindRaw(QHostAddress(pair->local->address), pair->local->port))
  {
    qDebug() << "Binding failed! Cannot send STUN Binding Requests to "
             << pair->remote->address << ":" << pair->remote->port;
    return false;
  }

  connect(&udp_, &UDPServer::rawMessageAvailable, this, &Stun::recvStunMessage);

  // TODO this code looks ugly -> refactor

  STUNMessage request = stunmsg_.createRequest();
  request.addAttribute(controller ? STUN_ATTR_ICE_CONTROLLING : STUN_ATTR_ICE_CONTROLLED);
  request.addAttribute(STUN_ATTR_PRIORITY, pair->priority);

  // we expect a response to this message from remote, by caching the TransactionID
  // and associated address port pair, we can succesfully validate the response TransactionID
  stunmsg_.expectReplyFrom(request, pair->remote->address, pair->remote->port);

  QByteArray message = stunmsg_.hostToNetwork(request);

  bool ok = false;

  for (int i = 0; i < 50; ++i)
  {
    udp_.sendData(message, QHostAddress(pair->remote->address), pair->remote->port, false);

    if (waitForStunResponse(20 * (i + 1)))
    {
      qDebug() << "got stun response!";
      ok = true;
      break;
    }
  }

  if (waitForStunResponse(100))
  {
    ok = true;
  }

  udp_.unbind();
  return ok;
}

bool Stun::sendBindingResponse(STUNMessage& request, QString addressRemote, int portRemote)
{
  STUNMessage response = stunmsg_.createResponse(request);

  response.addAttribute(STUN_ATTR_PRIORITY, 0x1337);

  request.addAttribute(
      request.hasAttribute(STUN_ATTR_ICE_CONTROLLED)
      ? STUN_ATTR_ICE_CONTROLLING
      : STUN_ATTR_ICE_CONTROLLED
  );

  QByteArray message = stunmsg_.hostToNetwork(response);

  for (int i = 0; i < 25; ++i)
  {
    udp_.sendData(message, QHostAddress(addressRemote), portRemote, false);
  }
}

// either we got Stun binding request -> send binding response
// or Stun binding response -> mark candidate as valid
void Stun::recvStunMessage(QNetworkDatagram message)
{
  QByteArray data      = message.data();
  STUNMessage stunMsg = stunmsg_.networkToHost(data);

  if (stunMsg.getType() == STUN_REQUEST)
  {
    if (stunmsg_.validateStunRequest(stunMsg))
    {
      stunmsg_.cacheRequest(stunMsg);

      if (stunMsg.hasAttribute(STUN_ATTR_USE_CANDIATE))
      {
        sendBindingResponse(stunMsg, message.senderAddress().toString(), message.senderPort());
        emit nominationRecv();
      }
      else
      {
        sendBindingResponse(stunMsg, message.senderAddress().toString(), message.senderPort());
      }
    }
  }
  else if (stunMsg.getType() == STUN_RESPONSE)
  {
    // if this message is a response to a request we just sent, its TransactionID should be cached
    // if not, vertaa viimeksi lähetetyn TransactionID:tä vasten
    if (stunmsg_.validateStunResponse(stunMsg, message.senderAddress(), message.senderPort()))
    {
      emit parsingDone();
    }
  }
  else
  {
    qDebug() << "WARNING: Got unkown STUN message, type: "      << stunMsg.getType()
             << " from " << message.senderAddress()      << ":" << message.senderPort()
             << " to"    << message.destinationAddress() << ":" << message.destinationPort();
    qDebug() << "\n\n\n\n";
    while (1);
  }
}

bool Stun::sendNominationRequest(ICEPair *pair)
{
  qDebug() << "[controller] BINDING " << pair->local->address << " TO PORT " << pair->local->port;

  if (!udp_.bindRaw(QHostAddress(pair->local->address), pair->local->port))
  {
    qDebug() << "Binding failed! Cannot send STUN Binding Requests to " << pair->remote->address << ":" << pair->remote->address;
    return false;
  }

  connect(&udp_, &UDPServer::rawMessageAvailable, this, &Stun::recvStunMessage);

  STUNMessage request = stunmsg_.createRequest();
  request.addAttribute(STUN_ATTR_ICE_CONTROLLING);
  request.addAttribute(STUN_ATTR_USE_CANDIATE);

  // expect reply for this message from remote
  stunmsg_.expectReplyFrom(request, pair->remote->address, pair->remote->port);

  QByteArray message  = stunmsg_.hostToNetwork(request);

  bool ok = false;

  for (int i = 0; i < 25; ++i)
  {
    udp_.sendData(message, QHostAddress(pair->remote->address), pair->remote->port, false);

    if (waitForStunResponse(20 * (i + 1)))
    {
      ok = true;
      break;
    }
  }

  udp_.unbind();
  return ok;
}

bool Stun::sendNominationResponse(ICEPair *pair)
{
  qDebug() << "[controllee] BINDING " << pair->local->address << " TO PORT " << pair->local->port;

  if (!udp_.bindRaw(QHostAddress(pair->local->address), pair->local->port))
  {
    qDebug() << "Binding failed! Cannot send STUN Binding Requests to " << pair->remote->address << ":" << pair->remote->address;
    return false;
  }

  connect(&udp_, &UDPServer::rawMessageAvailable, this, &Stun::recvStunMessage);

  // first send empty stun binding requests to remote to create a hole in the firewall
  // when the first nomination request is received (if any), start sending nomination response
  STUNMessage request = stunmsg_.createRequest();
  request.addAttribute(STUN_ATTR_ICE_CONTROLLED);

  QByteArray reqMessage = stunmsg_.hostToNetwork(request);
  bool nominationRecv   = false;

  for (int i = 0; i < 25; ++i)
  {
    udp_.sendData(reqMessage, QHostAddress(pair->remote->address), pair->remote->port, false);

    if (waitForNominationRequest(20 * (i + 1)))
    {
      nominationRecv = true;
      break;
    }
  }

  if (nominationRecv)
  {
    nominationRecv = false;

    STUNMessage response  = stunmsg_.createResponse();
    response.addAttribute(STUN_ATTR_ICE_CONTROLLED);
    response.addAttribute(STUN_ATTR_USE_CANDIATE);

    QByteArray respMessage = stunmsg_.hostToNetwork(response);

    for (int i = 0; i < 25; ++i)
    {
      udp_.sendData(respMessage, QHostAddress(pair->remote->address), pair->remote->port, false);

      // when we no longer get nomination request it means that remote has received
      // our response message and end the nomination process
      //
      // We can stop sending nomination responses when the waitForNominationRequest() timeouts
      //
      // Because we got here (we received nomination request in the previous step) we can assume
      // that the connection works in both ends and waitForNominationRequest() doesn't just timeout
      // because it doesn't receive anything
      if (!waitForNominationRequest(20 * (i + 1)))
      {
        nominationRecv = true;
        break;
      }
    }
  }

  udp_.unbind();
  return nominationRecv;
}

void Stun::processReply(QByteArray data)
{
  if(data.size() < 20)
  {
    qDebug() << "Received too small response to STUN query!";
    return;
  }

  QString message = QString::fromStdString(data.toHex().toStdString());
  qDebug() << "Got a STUN reply:" << message << "with size:" << data.size();

  STUNMessage response = stunmsg_.networkToHost(data);

  if (response.getType() != STUN_RESPONSE)
  {
    qDebug() << "Unsuccessful STUN transaction!";
    emit stunError();
    return;
  }

  if (response.getLength() == 0 || response.getCookie() != STUN_MAGIC_COOKIE)
  {
    qDebug() << "Something went wrong with STUN transaction values. Length:"
             << response.getLength() << "Magic cookie:" << response.getCookie();
    emit stunError();
    return;
  }

  if (!stunmsg_.verifyTransactionID(response))
  {
    qDebug() << "TransactionID is invalid!";
  }

  qDebug() << "Valid STUN response. Decoding address";

  std::pair<QHostAddress, uint16_t> addressInfo;

  if (response.getXorMappedAddress(addressInfo))
  {
    emit addressReceived(addressInfo.first);
  }
  else
  {
    qDebug() << "DIDN'T GET XOR-MAPPED-ADDRESS!";
    emit stunError();
  }
}
<commit_msg>Rewrite the STUN response parsing<commit_after>#include "stun.h"
#include "stunmsgfact.h"

#include <QDnsLookup>
#include <QHostInfo>
#include <QDateTime>
#include <QDebug>
#include <QMutex>
#include <QWaitCondition>
#include <QEventLoop>

#include <QtEndian>

const uint16_t GOOGLE_STUN_PORT = 19302;
const uint16_t STUN_PORT = 21000;

Stun::Stun():
  udp_(),
  stunmsg_()
{}

void Stun::wantAddress(QString stunServer)
{
  // To find the IP address of qt-project.org
  QHostInfo::lookupHost(stunServer, this, SLOT(handleHostaddress(QHostInfo)));
}

void Stun::handleHostaddress(QHostInfo info)
{
  const auto addresses = info.addresses();
  QHostAddress address;
  if(addresses.size() != 0)
  {
    address = addresses.at(0);
    qDebug() <<"Found" << addresses.size() << "stun server addresses. Using:" << address.toString();
  }
  else
  {
    qDebug() << "Did not find any addresses";
    return;
  }

  udp_.bind(QHostAddress::AnyIPv4, STUN_PORT);
  QObject::connect(&udp_, SIGNAL(messageAvailable(QByteArray)), this, SLOT(processReply(QByteArray)));

  STUNMessage request = stunmsg_.createRequest();
  QByteArray message  = stunmsg_.hostToNetwork(request);

  stunmsg_.cacheRequest(request);

  udp_.sendData(message, address, GOOGLE_STUN_PORT, false);
}

bool Stun::waitForStunResponse(unsigned long timeout)
{
  QTimer timer;
  timer.setSingleShot(true);
  QEventLoop loop;

  connect(this,   &Stun::parsingDone, &loop, &QEventLoop::quit);
  connect(&timer, &QTimer::timeout,   &loop, &QEventLoop::quit);

  timer.start(timeout);
  loop.exec();

  return timer.isActive();
}

bool Stun::waitForNominationRequest(unsigned long timeout)
{
  QTimer timer;
  timer.setSingleShot(true);
  QEventLoop loop;

  connect(this,   &Stun::nominationRecv, &loop, &QEventLoop::quit);
  connect(&timer, &QTimer::timeout,   &loop, &QEventLoop::quit);

  timer.start(timeout);
  loop.exec();

  return timer.isActive();
}

bool Stun::sendBindingRequest(ICEPair *pair, bool controller)
{
  if (controller)
    qDebug() << "[controller] BINDING " << pair->local->address<< " TO PORT " << pair->local->port;
  else
    qDebug() << "[controllee] BINDING " << pair->local->address << " TO PORT " << pair->local->port;

  if (!udp_.bindRaw(QHostAddress(pair->local->address), pair->local->port))
  {
    qDebug() << "Binding failed! Cannot send STUN Binding Requests to "
             << pair->remote->address << ":" << pair->remote->port;
    return false;
  }

  connect(&udp_, &UDPServer::rawMessageAvailable, this, &Stun::recvStunMessage);

  // TODO this code looks ugly -> refactor

  STUNMessage request = stunmsg_.createRequest();
  request.addAttribute(controller ? STUN_ATTR_ICE_CONTROLLING : STUN_ATTR_ICE_CONTROLLED);
  request.addAttribute(STUN_ATTR_PRIORITY, pair->priority);

  // we expect a response to this message from remote, by caching the TransactionID
  // and associated address port pair, we can succesfully validate the response TransactionID
  stunmsg_.expectReplyFrom(request, pair->remote->address, pair->remote->port);

  QByteArray message = stunmsg_.hostToNetwork(request);

  bool ok = false;

  for (int i = 0; i < 50; ++i)
  {
    udp_.sendData(message, QHostAddress(pair->remote->address), pair->remote->port, false);

    if (waitForStunResponse(20 * (i + 1)))
    {
      qDebug() << "got stun response!";
      ok = true;
      break;
    }
  }

  if (waitForStunResponse(100))
  {
    ok = true;
  }

  udp_.unbind();
  return ok;
}

bool Stun::sendBindingResponse(STUNMessage& request, QString addressRemote, int portRemote)
{
  STUNMessage response = stunmsg_.createResponse(request);

  response.addAttribute(STUN_ATTR_PRIORITY, 0x1337);

  request.addAttribute(
      request.hasAttribute(STUN_ATTR_ICE_CONTROLLED)
      ? STUN_ATTR_ICE_CONTROLLING
      : STUN_ATTR_ICE_CONTROLLED
  );

  QByteArray message = stunmsg_.hostToNetwork(response);

  for (int i = 0; i < 25; ++i)
  {
    udp_.sendData(message, QHostAddress(addressRemote), portRemote, false);
  }
}

// either we got Stun binding request -> send binding response
// or Stun binding response -> mark candidate as valid
void Stun::recvStunMessage(QNetworkDatagram message)
{
  QByteArray data      = message.data();
  STUNMessage stunMsg = stunmsg_.networkToHost(data);

  if (stunMsg.getType() == STUN_REQUEST)
  {
    if (stunmsg_.validateStunRequest(stunMsg))
    {
      stunmsg_.cacheRequest(stunMsg);

      if (stunMsg.hasAttribute(STUN_ATTR_USE_CANDIATE))
      {
        sendBindingResponse(stunMsg, message.senderAddress().toString(), message.senderPort());
        emit nominationRecv();
      }
      else
      {
        sendBindingResponse(stunMsg, message.senderAddress().toString(), message.senderPort());
      }
    }
  }
  else if (stunMsg.getType() == STUN_RESPONSE)
  {
    // if this message is a response to a request we just sent, its TransactionID should be cached
    // if not, vertaa viimeksi lähetetyn TransactionID:tä vasten
    if (stunmsg_.validateStunResponse(stunMsg, message.senderAddress(), message.senderPort()))
    {
      emit parsingDone();
    }
  }
  else
  {
    qDebug() << "WARNING: Got unkown STUN message, type: "      << stunMsg.getType()
             << " from " << message.senderAddress()      << ":" << message.senderPort()
             << " to"    << message.destinationAddress() << ":" << message.destinationPort();
    qDebug() << "\n\n\n\n";
    while (1);
  }
}

bool Stun::sendNominationRequest(ICEPair *pair)
{
  qDebug() << "[controller] BINDING " << pair->local->address << " TO PORT " << pair->local->port;

  if (!udp_.bindRaw(QHostAddress(pair->local->address), pair->local->port))
  {
    qDebug() << "Binding failed! Cannot send STUN Binding Requests to " << pair->remote->address << ":" << pair->remote->address;
    return false;
  }

  connect(&udp_, &UDPServer::rawMessageAvailable, this, &Stun::recvStunMessage);

  STUNMessage request = stunmsg_.createRequest();
  request.addAttribute(STUN_ATTR_ICE_CONTROLLING);
  request.addAttribute(STUN_ATTR_USE_CANDIATE);

  // expect reply for this message from remote
  stunmsg_.expectReplyFrom(request, pair->remote->address, pair->remote->port);

  QByteArray message  = stunmsg_.hostToNetwork(request);

  bool ok = false;

  for (int i = 0; i < 25; ++i)
  {
    udp_.sendData(message, QHostAddress(pair->remote->address), pair->remote->port, false);

    if (waitForStunResponse(20 * (i + 1)))
    {
      ok = true;
      break;
    }
  }

  udp_.unbind();
  return ok;
}

bool Stun::sendNominationResponse(ICEPair *pair)
{
  qDebug() << "[controllee] BINDING " << pair->local->address << " TO PORT " << pair->local->port;

  if (!udp_.bindRaw(QHostAddress(pair->local->address), pair->local->port))
  {
    qDebug() << "Binding failed! Cannot send STUN Binding Requests to " << pair->remote->address << ":" << pair->remote->address;
    return false;
  }

  connect(&udp_, &UDPServer::rawMessageAvailable, this, &Stun::recvStunMessage);

  // first send empty stun binding requests to remote to create a hole in the firewall
  // when the first nomination request is received (if any), start sending nomination response
  STUNMessage request = stunmsg_.createRequest();
  request.addAttribute(STUN_ATTR_ICE_CONTROLLED);

  QByteArray reqMessage = stunmsg_.hostToNetwork(request);
  bool nominationRecv   = false;

  for (int i = 0; i < 25; ++i)
  {
    udp_.sendData(reqMessage, QHostAddress(pair->remote->address), pair->remote->port, false);

    if (waitForNominationRequest(20 * (i + 1)))
    {
      nominationRecv = true;
      break;
    }
  }

  if (nominationRecv)
  {
    nominationRecv = false;

    STUNMessage response  = stunmsg_.createResponse();
    response.addAttribute(STUN_ATTR_ICE_CONTROLLED);
    response.addAttribute(STUN_ATTR_USE_CANDIATE);

    QByteArray respMessage = stunmsg_.hostToNetwork(response);

    for (int i = 0; i < 25; ++i)
    {
      udp_.sendData(respMessage, QHostAddress(pair->remote->address), pair->remote->port, false);

      // when we no longer get nomination request it means that remote has received
      // our response message and end the nomination process
      //
      // We can stop sending nomination responses when the waitForNominationRequest() timeouts
      //
      // Because we got here (we received nomination request in the previous step) we can assume
      // that the connection works in both ends and waitForNominationRequest() doesn't just timeout
      // because it doesn't receive anything
      if (!waitForNominationRequest(20 * (i + 1)))
      {
        nominationRecv = true;
        break;
      }
    }
  }

  udp_.unbind();
  return nominationRecv;
}

void Stun::processReply(QByteArray data)
{
  if(data.size() < 20)
  {
    qDebug() << "Received too small response to STUN query!";
    return;
  }

  QString message = QString::fromStdString(data.toHex().toStdString());
  qDebug() << "Got a STUN reply:" << message << "with size:" << data.size();

  STUNMessage response = stunmsg_.networkToHost(data);

  if (!stunmsg_.validateStunResponse(response))
  {
    qDebug() << "Invalid STUN Response!";
    emit stunError();
    return;
  }

  std::pair<QHostAddress, uint16_t> addressInfo;

  if (response.getXorMappedAddress(addressInfo))
  {
    emit addressReceived(addressInfo.first);
  }
  else
  {
    qDebug() << "DIDN'T GET XOR-MAPPED-ADDRESS!";
    emit stunError();
  }
}
<|endoftext|>


<commit_before>/**
 * @file
 * brief description, full stop.
 *
 * long description, many sentences.
 *
 */
#include "angort.h"

#include "ser.h"
#include "file.h"
#include "opcodes.h"

void CodeType::set(Value *v,const struct CodeBlock *cb){
    v->clr();
    v->v.cb=cb;
    v->t = Types::tCode;
}

void CodeType::saveValue(Serialiser *ser, Value *v){
    ser->file->write32(ser->getFixupByData(v->v.cb));
}
void CodeType::loadValue(Serialiser *ser, Value *v){
    v->setFixup(ser->file->read32());
}

void CodeType::saveDataBlock(Serialiser *ser,const void *v){
    const CodeBlock *cb = (CodeBlock *)v;
    cb->save(ser);
}

void CodeBlock::save(Serialiser *ser) const {
    File *f = ser->file;

    f->write16(size);
    f->write16(locals);
    f->write16(params);
    f->write16(closureMapCt);
    f->writeString(spec);

    // save closure map
    for(int i=0;i<closureMapCt;i++){
        f->write16(closureMap[i].parent);
        f->write16(closureMap[i].isLocalInParent ? 1 : 0);
    }

    // save instructions
    const Instruction *p = ip;
    for(int i=0;i<size;i++,p++){
        int opcode = p->opcode;
        // change the opcode for these, to indicate the data
        // is now a fixup index
        switch(p->opcode){
        case OP_LITERALSTRING:
            opcode = OP_LITERALSTRING_FIXUP;
            break;
        case OP_LITERALCODE:
            opcode = OP_LITERALCODE_FIXUP;
            break;
        default:break;
        }

        f->write16(opcode);

        switch(p->opcode){
        case OP_LITERALINT:
        case OP_CLOSUREGET:
        case OP_CLOSURESET:
        case OP_LOCALSET:
        case OP_LOCALGET:
        case OP_GLOBALSET:
        case OP_GLOBALGET:
        case OP_CONSTSET:
        case OP_CONSTGET:
        case OP_WORD:
        case OP_IF:
        case OP_LEAVE:
        case OP_IFLEAVE:
        case OP_DECLEAVENEG:
        case OP_ITERLEAVEIFDONE:
        case OP_JUMP:
            f->writeInt(p->d.i);
            break;
        case OP_PROPSET:
        case OP_PROPGET:
            f->writeString(ser->angort->props.getKey(p->d.prop));
            break;
        case OP_LITERALFLOAT:
            f->writeFloat(p->d.f);
            break;
        case OP_LITERALSTRING:
            f->write32(ser->getFixupByData(p->d.cb));
            break;
        case OP_LITERALCODE:
            f->write32(ser->getFixupByData(p->d.s));
            break;
        case OP_FUNC:
            f->writeString(ser->angort->funcs.getKey(p->d.func));
            break;
        default:
            break;
        }
    }
}

void *CodeType::loadDataBlock(Serialiser *ser){
    return (void *)new CodeBlock(ser);

}

CodeBlock::CodeBlock(Serialiser *ser){
    char buf[1024];

    File *f = ser->file;

    size = f->read16();
    locals = f->read16();
    params = f->read16();
    closureMapCt = f->read16();
    spec = f->readStringAlloc();

    printf("Reading %d, locals %d, params %d, closureMapCt %d\n",
           size,locals,params,closureMapCt);

    // load closure map
    closureMap = new ClosureMapEntry[closureMapCt];
    for(int i=0;i<closureMapCt;i++){
        closureMap[i].parent = f->read16();
        closureMap[i].isLocalInParent = (f->read16()==1);
    }

    // load instructions
    ip = new Instruction[size];
    Instruction *p = (Instruction *)ip;

    for(int i=0;i<size;i++,p++){
        p->opcode = f->read16();

        switch(p->opcode){
        case OP_LITERALINT:
        case OP_CLOSUREGET:
        case OP_CLOSURESET:
        case OP_LOCALSET:
        case OP_LOCALGET:
        case OP_GLOBALSET:
        case OP_GLOBALGET:
        case OP_CONSTSET:
        case OP_CONSTGET:
        case OP_WORD:
        case OP_IF:
        case OP_LEAVE:
        case OP_IFLEAVE:
        case OP_DECLEAVENEG:
        case OP_ITERLEAVEIFDONE:
        case OP_JUMP:
            p->d.i = f->readInt();
            break;
        case OP_PROPSET:
        case OP_PROPGET:
            f->readString(buf,1024);
            p->d.prop = ser->angort->props.get(buf);
            break;
        case OP_LITERALFLOAT:
            p->d.f = f->readFloat();
            break;
        case OP_LITERALCODE_FIXUP:
        case OP_LITERALSTRING_FIXUP:
            p->d.fixup = f->read32();
            break;
        case OP_FUNC:
            f->readString(buf,1024);
            p->d.func =  ser->angort->funcs.get(buf);
            break;
        case OP_LITERALSTRING:
        case OP_LITERALCODE:
            throw WTF; // should be a fixup!
        default:
            break;
        }
    }

}

<commit_msg>Save fixed. Again.<commit_after>/**
 * @file
 * brief description, full stop.
 *
 * long description, many sentences.
 *
 */
#include "angort.h"

#include "ser.h"
#include "file.h"
#include "opcodes.h"

void CodeType::set(Value *v,const struct CodeBlock *cb){
    v->clr();
    v->v.cb=cb;
    v->t = Types::tCode;
}

void CodeType::saveValue(Serialiser *ser, Value *v){
    ser->file->write32(ser->getFixupByData(v->v.cb));
}
void CodeType::loadValue(Serialiser *ser, Value *v){
    v->setFixup(ser->file->read32());
}

void CodeType::saveDataBlock(Serialiser *ser,const void *v){
    const CodeBlock *cb = (CodeBlock *)v;
    cb->save(ser);
}

void CodeBlock::save(Serialiser *ser) const {
    File *f = ser->file;

    f->write16(size);
    f->write16(locals);
    f->write16(params);
    f->write16(closureMapCt);
    f->writeString(spec?spec:"");

    // save closure map
    for(int i=0;i<closureMapCt;i++){
        f->write16(closureMap[i].parent);
        f->write16(closureMap[i].isLocalInParent ? 1 : 0);
    }

    // save instructions
    const Instruction *p = ip;
    for(int i=0;i<size;i++,p++){
        int opcode = p->opcode;
        // change the opcode for these, to indicate the data
        // is now a fixup index
        switch(p->opcode){
        case OP_LITERALSTRING:
            opcode = OP_LITERALSTRING_FIXUP;
            break;
        case OP_LITERALCODE:
            opcode = OP_LITERALCODE_FIXUP;
            break;
        default:break;
        }

        f->write16(opcode);

        switch(p->opcode){
        case OP_LITERALINT:
        case OP_CLOSUREGET:
        case OP_CLOSURESET:
        case OP_LOCALSET:
        case OP_LOCALGET:
        case OP_GLOBALSET:
        case OP_GLOBALGET:
        case OP_CONSTSET:
        case OP_CONSTGET:
        case OP_WORD:
        case OP_IF:
        case OP_LEAVE:
        case OP_IFLEAVE:
        case OP_DECLEAVENEG:
        case OP_ITERLEAVEIFDONE:
        case OP_JUMP:
            f->writeInt(p->d.i);
            break;
        case OP_PROPSET:
        case OP_PROPGET:
            f->writeString(ser->angort->props.getKey(p->d.prop));
            break;
        case OP_LITERALFLOAT:
            f->writeFloat(p->d.f);
            break;
        case OP_LITERALSTRING:
            f->write32(ser->getFixupByData(p->d.cb));
            break;
        case OP_LITERALCODE:
            f->write32(ser->getFixupByData(p->d.s));
            break;
        case OP_FUNC:
            f->writeString(ser->angort->funcs.getKey(p->d.func));
            break;
        default:
            break;
        }
    }
}

void *CodeType::loadDataBlock(Serialiser *ser){
    return (void *)new CodeBlock(ser);

}

CodeBlock::CodeBlock(Serialiser *ser){
    char buf[1024];

    File *f = ser->file;

    size = f->read16();
    locals = f->read16();
    params = f->read16();
    closureMapCt = f->read16();
    spec = f->readStringAlloc();

    printf("Reading %d, locals %d, params %d, closureMapCt %d\n",
           size,locals,params,closureMapCt);

    // load closure map
    closureMap = new ClosureMapEntry[closureMapCt];
    for(int i=0;i<closureMapCt;i++){
        closureMap[i].parent = f->read16();
        closureMap[i].isLocalInParent = (f->read16()==1);
    }

    // load instructions
    ip = new Instruction[size];
    Instruction *p = (Instruction *)ip;

    for(int i=0;i<size;i++,p++){
        p->opcode = f->read16();

        switch(p->opcode){
        case OP_LITERALINT:
        case OP_CLOSUREGET:
        case OP_CLOSURESET:
        case OP_LOCALSET:
        case OP_LOCALGET:
        case OP_GLOBALSET:
        case OP_GLOBALGET:
        case OP_CONSTSET:
        case OP_CONSTGET:
        case OP_WORD:
        case OP_IF:
        case OP_LEAVE:
        case OP_IFLEAVE:
        case OP_DECLEAVENEG:
        case OP_ITERLEAVEIFDONE:
        case OP_JUMP:
            p->d.i = f->readInt();
            break;
        case OP_PROPSET:
        case OP_PROPGET:
            f->readString(buf,1024);
            p->d.prop = ser->angort->props.get(buf);
            break;
        case OP_LITERALFLOAT:
            p->d.f = f->readFloat();
            break;
        case OP_LITERALCODE_FIXUP:
        case OP_LITERALSTRING_FIXUP:
            p->d.fixup = f->read32();
            break;
        case OP_FUNC:
            f->readString(buf,1024);
            p->d.func =  ser->angort->funcs.get(buf);
            break;
        case OP_LITERALSTRING:
        case OP_LITERALCODE:
            throw WTF; // should be a fixup!
        default:
            break;
        }
    }

}

<|endoftext|>