<commit_before>#include "gtest/gtest.h"

#include <stdexcept>

#include "Token.hpp"
#include "Instruction.hpp"

class SemanticAnalyser
{
public:
  class InvalidSemantic : public std::runtime_error
  {
  public:
    InvalidSemantic(const std::string& msg) : std::runtime_error{msg}
    {
    }
  };

  Instructions analyse(const Tokens& tokens)
  {
    if (tokens.empty())
    {
      return {};
    }
    if (tokens.size() == 3)
    {
      return {{InstructionType::LdA, 0}};
    }
    throw InvalidSemantic{"Invalid number of tokens"};
  }

private:
  using Transition = std::pair<TokenType, TokenType>;
  using Transitions = std::vector<Transition>;

  Transitions validTransitions;
};

using namespace ::testing;

struct SemanticAnalyserTest : public Test
{
  SemanticAnalyser analyser;

  static constexpr Token createTokenWithZeroValue(TokenType type)
  {
    return{type, 0};
  }

  static constexpr Instruction createInstructionWithZeroValue(InstructionType type)
  {
    return{type, 0};
  }
};

TEST_F(SemanticAnalyserTest, ShouldAcceptEmptyTokens)
{
  Tokens tokens{};
  Instructions instructions;
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstructionSet)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld)};
  ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptValidLdInstructions)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                createTokenWithZeroValue(TokenType::A),
                createTokenWithZeroValue(TokenType::Number8Bit)};
  Instructions instructions{createInstructionWithZeroValue(InstructionType::LdA)};
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}
<commit_msg>SemanticAnalyser Returs Out instruction<commit_after>#include "gtest/gtest.h"

#include <stdexcept>

#include "Token.hpp"
#include "Instruction.hpp"

class SemanticAnalyser
{
public:
  class InvalidSemantic : public std::runtime_error
  {
  public:
    InvalidSemantic(const std::string& msg) : std::runtime_error{msg}
    {
    }
  };

  Instructions analyse(const Tokens& tokens)
  {
    if (tokens.empty())
    {
      return {};
    }
    if (tokens.size() == 3)
    {
      if (tokens.at(0).type == TokenType::Ld)
      {
        return {{InstructionType::LdA, 0}};
      }
      else
      {
        return {{InstructionType::OutA, 0}};
      }
    }
    throw InvalidSemantic{"Invalid number of tokens"};
  }

private:
  using Transition = std::pair<TokenType, TokenType>;
  using Transitions = std::vector<Transition>;

  Transitions validTransitions;
};

using namespace ::testing;

struct SemanticAnalyserTest : public Test
{
  SemanticAnalyser analyser;

  static constexpr Token createTokenWithZeroValue(TokenType type)
  {
    return{type, 0};
  }

  static constexpr Instruction createInstructionWithZeroValue(InstructionType type)
  {
    return{type, 0};
  }
};

TEST_F(SemanticAnalyserTest, ShouldAcceptEmptyTokens)
{
  Tokens tokens{};
  Instructions instructions;
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstructionSet)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld)};
  ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldAcceptLdInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                createTokenWithZeroValue(TokenType::A),
                createTokenWithZeroValue(TokenType::Number8Bit)};
  Instructions instructions{createInstructionWithZeroValue(InstructionType::LdA)};
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                createTokenWithZeroValue(TokenType::ZeroWithBrackets),
                createTokenWithZeroValue(TokenType::A)};
  Instructions instructions{createInstructionWithZeroValue(InstructionType::OutA)};
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}
<|endoftext|>


<commit_before>/*
 * FrameStatistics_Service.cpp
 *
 * Copyright (C) 2020 by MegaMol Team
 * Alle Rechte vorbehalten.
 */

// search/replace FrameStatistics_Service with your class name
// you should also delete the FAQ comments in these template files after you read and understood them
#include "FrameStatistics_Service.hpp"

#include <chrono>
#include <numeric>
#include <sstream>

#include "mmcore/utility/Timestamp.h"

#include "LuaCallbacksCollection.h"

// local logging wrapper for your convenience until central MegaMol logger established
#include "mmcore/utility/log/Log.h"
static void log(const char* text) {
    const std::string msg = "FrameStatistics_Service: " + std::string(text);
    megamol::core::utility::log::Log::DefaultLog.WriteInfo(msg.c_str());
}
static void log(std::string text) {
    log(text.c_str());
}

namespace megamol {
namespace frontend {

FrameStatistics_Service::FrameStatistics_Service() {}

FrameStatistics_Service::~FrameStatistics_Service() {}

bool FrameStatistics_Service::init(void* configPtr) {
    if (configPtr == nullptr)
        return false;

    return init(*static_cast<Config*>(configPtr));
}

bool FrameStatistics_Service::init(const Config& config) {

    this->m_requestedResourcesNames = {//"IOpenGL_Context", // for GL-specific measures?
        "RegisterLuaCallbacks"};

    m_program_start_time = std::chrono::steady_clock::time_point::clock::now();

    log("initialized successfully");
    return true;
}

void FrameStatistics_Service::close() {}

std::vector<FrontendResource>& FrameStatistics_Service::getProvidedResources() {
    m_providedResourceReferences = {{frontend_resources::FrameStatistics_Req_Name, m_statistics}};

    return m_providedResourceReferences;
}

const std::vector<std::string> FrameStatistics_Service::getRequestedResourceNames() const {
    return m_requestedResourcesNames;
}

void FrameStatistics_Service::setRequestedResources(std::vector<FrontendResource> resources) {
    this->m_requestedResourceReferences = resources;
    fill_lua_callbacks();
}

void FrameStatistics_Service::updateProvidedResources() {
    start_frame();
}

void FrameStatistics_Service::digestChangedRequestedResources() {}

void FrameStatistics_Service::resetProvidedResources() {
    finish_frame();
}

void FrameStatistics_Service::preGraphRender() {}

void FrameStatistics_Service::postGraphRender() {}

// TODO: maybe port FPS Counter from
// #include "vislib/graphics/FpsCounter.h"
void FrameStatistics_Service::start_frame() {
    m_frame_start_time = std::chrono::steady_clock::time_point::clock::now();
}

void FrameStatistics_Service::finish_frame() {
    auto now = std::chrono::steady_clock::time_point::clock::now();

    m_statistics.rendered_frames_count++;

    m_statistics.elapsed_program_time_seconds =
        static_cast<double>(std::chrono::duration_cast<std::chrono::seconds>(now - m_program_start_time).count());

    const auto last_frame_till_now_micro =
        std::chrono::duration_cast<std::chrono::microseconds>(now - m_frame_start_time).count();

    m_statistics.last_rendered_frame_time_milliseconds = static_cast<double>(last_frame_till_now_micro) / 1000.0;

    m_frame_times_micro[m_ring_buffer_ptr] = last_frame_till_now_micro;
    m_ring_buffer_ptr = (m_ring_buffer_ptr + 1) % m_frame_times_micro.size();

    m_statistics.last_averaged_mspf = std::accumulate(m_frame_times_micro.begin(), m_frame_times_micro.end(), 0) /
                                      m_frame_times_micro.size() / static_cast<double>(1000);
    m_statistics.last_averaged_fps = 1000.0 / m_statistics.last_averaged_mspf;
}

void FrameStatistics_Service::fill_lua_callbacks() {
    frontend_resources::LuaCallbacksCollection callbacks;

    callbacks.add<frontend_resources::LuaCallbacksCollection::StringResult>("mmGetTimeStamp",
        "(void)\n\tReturns a timestamp in ISO format.",
        {[&]() -> frontend_resources::LuaCallbacksCollection::StringResult {
            auto const tp = std::chrono::system_clock::now();
            auto const timestamp = core::utility::serialize_timestamp(tp);
            return frontend_resources::LuaCallbacksCollection::StringResult(timestamp);
        }});

    auto& register_callbacks =
        m_requestedResourceReferences[0]
            .getResource<std::function<void(frontend_resources::LuaCallbacksCollection const&)>>();

    register_callbacks(callbacks);
}

} // namespace frontend
} // namespace megamol
<commit_msg>fixed broken timer fix<commit_after>/*
 * FrameStatistics_Service.cpp
 *
 * Copyright (C) 2020 by MegaMol Team
 * Alle Rechte vorbehalten.
 */

// search/replace FrameStatistics_Service with your class name
// you should also delete the FAQ comments in these template files after you read and understood them
#include "FrameStatistics_Service.hpp"

#include <chrono>
#include <numeric>
#include <sstream>

#include "mmcore/utility/Timestamp.h"

#include "LuaCallbacksCollection.h"

// local logging wrapper for your convenience until central MegaMol logger established
#include "mmcore/utility/log/Log.h"
static void log(const char* text) {
    const std::string msg = "FrameStatistics_Service: " + std::string(text);
    megamol::core::utility::log::Log::DefaultLog.WriteInfo(msg.c_str());
}
static void log(std::string text) {
    log(text.c_str());
}

namespace megamol {
namespace frontend {

FrameStatistics_Service::FrameStatistics_Service() {}

FrameStatistics_Service::~FrameStatistics_Service() {}

bool FrameStatistics_Service::init(void* configPtr) {
    if (configPtr == nullptr)
        return false;

    return init(*static_cast<Config*>(configPtr));
}

bool FrameStatistics_Service::init(const Config& config) {

    this->m_requestedResourcesNames = {//"IOpenGL_Context", // for GL-specific measures?
        "RegisterLuaCallbacks"};

    m_program_start_time = std::chrono::steady_clock::time_point::clock::now();

    log("initialized successfully");
    return true;
}

void FrameStatistics_Service::close() {}

std::vector<FrontendResource>& FrameStatistics_Service::getProvidedResources() {
    m_providedResourceReferences = {{frontend_resources::FrameStatistics_Req_Name, m_statistics}};

    return m_providedResourceReferences;
}

const std::vector<std::string> FrameStatistics_Service::getRequestedResourceNames() const {
    return m_requestedResourcesNames;
}

void FrameStatistics_Service::setRequestedResources(std::vector<FrontendResource> resources) {
    this->m_requestedResourceReferences = resources;
    fill_lua_callbacks();
}

void FrameStatistics_Service::updateProvidedResources() {
    start_frame();
}

void FrameStatistics_Service::digestChangedRequestedResources() {}

void FrameStatistics_Service::resetProvidedResources() {
    finish_frame();
}

void FrameStatistics_Service::preGraphRender() {}

void FrameStatistics_Service::postGraphRender() {}

// TODO: maybe port FPS Counter from
// #include "vislib/graphics/FpsCounter.h"
void FrameStatistics_Service::start_frame() {
    m_frame_start_time = std::chrono::steady_clock::time_point::clock::now();
}

void FrameStatistics_Service::finish_frame() {
    auto now = std::chrono::steady_clock::time_point::clock::now();

    m_statistics.rendered_frames_count++;

    using double_seconds = std::chrono::duration<double>;
    using double_microseconds = std::chrono::duration<double, std::micro>;

    m_statistics.elapsed_program_time_seconds = double_seconds(now - m_program_start_time).count();
    const auto last_frame_till_now_micro = double_microseconds(now - m_frame_start_time).count();

    m_statistics.last_rendered_frame_time_milliseconds = last_frame_till_now_micro / 1000.0;

    m_frame_times_micro[m_ring_buffer_ptr] = static_cast<long long>(last_frame_till_now_micro);
    m_ring_buffer_ptr = (m_ring_buffer_ptr + 1) % m_frame_times_micro.size();

    m_statistics.last_averaged_mspf = std::accumulate(m_frame_times_micro.begin(), m_frame_times_micro.end(), 0) /
                                      m_frame_times_micro.size() / static_cast<double>(1000);
    m_statistics.last_averaged_fps = 1000.0 / m_statistics.last_averaged_mspf;
}

void FrameStatistics_Service::fill_lua_callbacks() {
    frontend_resources::LuaCallbacksCollection callbacks;

    callbacks.add<frontend_resources::LuaCallbacksCollection::StringResult>("mmGetTimeStamp",
        "(void)\n\tReturns a timestamp in ISO format.",
        {[&]() -> frontend_resources::LuaCallbacksCollection::StringResult {
            auto const tp = std::chrono::system_clock::now();
            auto const timestamp = core::utility::serialize_timestamp(tp);
            return frontend_resources::LuaCallbacksCollection::StringResult(timestamp);
        }});

    auto& register_callbacks =
        m_requestedResourceReferences[0]
            .getResource<std::function<void(frontend_resources::LuaCallbacksCollection const&)>>();

    register_callbacks(callbacks);
}

} // namespace frontend
} // namespace megamol
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Advanced Normalization Tools
  Module:    $RCSfile: AverageImages.cxx,v $
  Language:  C++
  Date:      $Date: 2009/01/27 23:25:24 $
  Version:   $Revision: 1.21 $

  Copyright (c) ConsortiumOfANTS. All rights reserved.
  See accompanying COPYING.txt or
 http://sourceforge.net/projects/advants/files/ANTS/ANTSCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// We divide the 2nd input image by its mean and add it to the first
// input image with weight 1/n.
// The output overwrites the 1st img with the sum.

// Note: could easily add variance computation
// http://people.revoledu.com/kardi/tutorial/RecursiveStatistic/Time-Variance.htm

#include "itkArray.h"
#include "itkVariableLengthVector.h"
#include "itkImage.h"
#include "itkImageRegionConstIterator.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIteratorWithIndex.h"
#include "itkOptimalSharpeningImageFilter.h"

template <unsigned int ImageDimension, unsigned int NVectorComponents>
int AverageImages1(unsigned int argc, char *argv[])
{
  typedef float                                        PixelType;
  typedef itk::Image<PixelType, ImageDimension>        ImageType;
  typedef itk::ImageRegionIteratorWithIndex<ImageType> Iterator;
  typedef itk::ImageFileReader<ImageType>              ImageFileReader;
  typedef itk::ImageFileWriter<ImageType>              writertype;

  bool  normalizei = atoi(argv[3]);
  float numberofimages = (float)argc - 4.;
  typename ImageType::Pointer averageimage = NULL;
  typename ImageType::Pointer image2 = NULL;

  typename ImageType::SizeType size;
  size.Fill(0);
  unsigned int bigimage = 0;
  for( unsigned int j = 4; j < argc; j++ )
    {
    // Get the image dimension
    std::string fn = std::string(argv[j]);
    std::cout << " fn " << fn << std::endl;
    typename itk::ImageIOBase::Pointer imageIO =
      itk::ImageIOFactory::CreateImageIO(fn.c_str(), itk::ImageIOFactory::ReadMode);
    imageIO->SetFileName(fn.c_str() );
    imageIO->ReadImageInformation();
    for( unsigned int i = 0; i < imageIO->GetNumberOfDimensions(); i++ )
      {
      if( imageIO->GetDimensions(i) > size[i] )
        {
        size[i] = imageIO->GetDimensions(i);
        bigimage = j;
        std::cout << " bigimage " << j << " size " << size << std::endl;
        }
      }
    }

  std::cout << " largest image " << size << std::endl;
  typename ImageFileReader::Pointer reader = ImageFileReader::New();
  reader->SetFileName(argv[bigimage]);
  reader->Update();
  averageimage = reader->GetOutput();
  unsigned int vectorlength = reader->GetImageIO()->GetNumberOfComponents();
  std::cout << " Averaging " << numberofimages << " images with dim = " << ImageDimension << " vector components "
            << vectorlength << std::endl;
  PixelType meanval = 0;
  averageimage->FillBuffer(meanval);
  for( unsigned int j = 4; j < argc; j++ )
    {
    std::cout << " reading " << std::string(argv[j]) << std::endl;
    typename ImageFileReader::Pointer reader = ImageFileReader::New();
    reader->SetFileName(argv[j]);
    reader->Update();
    image2 = reader->GetOutput();
    Iterator      vfIter2( image2,  image2->GetLargestPossibleRegion() );
    unsigned long ct = 0;
    if( normalizei )
      {
      meanval = 0;
      for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
        {
        PixelType localp = image2->GetPixel( vfIter2.GetIndex() );
        meanval = meanval + localp;
        ct++;
        }
      if( ct > 0 )
        {
        meanval = meanval / (float)ct;
        }
      if( meanval <= 0 )
        {
        meanval = (1);
        }
      }
    for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
      {
      PixelType val = vfIter2.Get();
      if( normalizei )
        {
        val /= meanval;
        }
      val = val / (float)numberofimages;
      PixelType oldval = averageimage->GetPixel(vfIter2.GetIndex() );
      averageimage->SetPixel(vfIter2.GetIndex(), val + oldval );
      }
    }

  typedef itk::OptimalSharpeningImageFilter<ImageType, ImageType> sharpeningFilter;
  typename sharpeningFilter::Pointer shFilter = sharpeningFilter::New();
  if( normalizei && argc > 3 && vectorlength == 1 )
    {
    shFilter->SetInput( averageimage );
    shFilter->SetSValue(0.5);
    averageimage =  shFilter->GetOutput();
    }

  std::cout << " writing output ";
    {
    typename writertype::Pointer writer = writertype::New();
    writer->SetFileName(argv[2]);
    writer->SetInput( averageimage );
    writer->Update();
    }

  return 0;
}

template <unsigned int ImageDimension, unsigned int NVectorComponents>
int AverageImages(unsigned int argc, char *argv[])
{
  typedef itk::Vector<float, NVectorComponents>        PixelType;
  typedef itk::Image<PixelType, ImageDimension>        ImageType;
  typedef itk::ImageRegionIteratorWithIndex<ImageType> Iterator;
  typedef itk::ImageFileReader<ImageType>              ImageFileReader;
  typedef itk::ImageFileWriter<ImageType>              writertype;

  bool  normalizei = atoi(argv[3]);
  float numberofimages = (float)argc - 4.;
  typename ImageType::Pointer averageimage = NULL;
  typename ImageType::Pointer image2 = NULL;

  typename ImageType::SizeType size;
  size.Fill(0);
  unsigned int bigimage = 0;
  for( unsigned int j = 4; j < argc; j++ )
    {
    // Get the image dimension
    std::string fn = std::string(argv[j]);
    std::cout << " fn " << fn << std::endl;
    typename itk::ImageIOBase::Pointer imageIO =
      itk::ImageIOFactory::CreateImageIO(fn.c_str(), itk::ImageIOFactory::ReadMode);
    imageIO->SetFileName(fn.c_str() );
    imageIO->ReadImageInformation();
    for( unsigned int i = 0; i < imageIO->GetNumberOfDimensions(); i++ )
      {
      if( imageIO->GetDimensions(i) > size[i] )
        {
        size[i] = imageIO->GetDimensions(i);
        bigimage = j;
        std::cout << " bigimage " << j << " size " << size << std::endl;
        }
      }
    }

  std::cout << " largest image " << size << std::endl;
  typename ImageFileReader::Pointer reader = ImageFileReader::New();
  reader->SetFileName(argv[bigimage]);
  reader->Update();
  averageimage = reader->GetOutput();
  unsigned int vectorlength = reader->GetImageIO()->GetNumberOfComponents();
  std::cout << " Averaging " << numberofimages << " images with dim = " << ImageDimension << " vector components "
            << vectorlength << std::endl;
  typename ImageType::IndexType zindex; zindex.Fill(0);
  PixelType meanval = reader->GetOutput()->GetPixel(zindex);
  meanval.Fill(0);
  averageimage->FillBuffer(meanval);
  for( unsigned int j = 4; j < argc; j++ )
    {
    std::cout << " reading " << std::string(argv[j]) << std::endl;
    typename ImageFileReader::Pointer reader = ImageFileReader::New();
    reader->SetFileName(argv[j]);
    reader->Update();
    image2 = reader->GetOutput();
    Iterator      vfIter2( image2,  image2->GetLargestPossibleRegion() );
    unsigned long ct = 0;
    if( normalizei )
      {
      meanval.Fill(0);
      for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
        {
        PixelType localp = image2->GetPixel( vfIter2.GetIndex() );
        meanval = meanval + localp;
        ct++;
        }
      if( ct > 0 )
        {
        meanval = meanval / (float)ct;
        }
      if( meanval.GetNorm() <= 0 )
        {
        meanval.Fill(1);
        }
      }
    for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
      {
      PixelType val = vfIter2.Get();
      if( normalizei )
        {
        for( unsigned int k = 0; k < vectorlength; k++ )
          {
          val[k] /= meanval[k];
          }
        }
      val = val / (float)numberofimages;
      PixelType oldval = averageimage->GetPixel(vfIter2.GetIndex() );
      averageimage->SetPixel(vfIter2.GetIndex(), val + oldval );
      }
    }

    {
    typename writertype::Pointer writer = writertype::New();
    writer->SetFileName(argv[2]);
    writer->SetInput( averageimage );
    writer->Update();
    }

  return 0;
}

int main(int argc, char * argv[])
{
  if( argc < 3 )
    {
    std::cout << "\n" << std::endl;
    std::cout << "Usage: \n" << std::endl;
    std::cout << argv[0] << " ImageDimension Outputfname.nii.gz Normalize <images> \n" << std::endl;
    std::cout << " Compulsory arguments: \n" << std::endl;
    std::cout << " ImageDimension: 2 or 3 (for 2 or 3 dimensional input).\n " << std::endl;
    std::cout << " Outputfname.nii.gz: the name of the resulting image.\n" << std::endl;
    std::cout
      <<
    " Normalize: 0 (false) or 1 (true); if true, the 2nd image is divided by its mean. This will select the largest image to average into.\n"
      << std::endl;
    std::cout << " Example Usage:\n" << std::endl;
    std::cout << argv[0] << " 3 average.nii.gz  1  *.nii.gz \n" << std::endl;
    std::cout << " \n" << std::endl;
    return 1;
    }

  int                       dim = atoi( argv[1] );
  itk::ImageIOBase::Pointer imageIO =
    itk::ImageIOFactory::CreateImageIO(argv[4], itk::ImageIOFactory::ReadMode);
  imageIO->SetFileName(argv[4]);
  imageIO->ReadImageInformation();
  unsigned int ncomponents = imageIO->GetNumberOfComponents();

  // Get the image dimension
  switch( atoi(argv[1]) )
    {
    case 2:
      {
      switch( ncomponents )
        {
        case 2:
          {
          AverageImages<2, 2>(argc, argv);
          }
          break;
        default:
          {
          AverageImages1<2, 1>(argc, argv);
          }
          break;
        }
      }
      break;
    case 3:
      {
      switch( ncomponents )
        {
        case 7:
          {
          AverageImages<3, 7>(argc, argv);
          }
          break;
        case 6:
          {
          AverageImages<3, 6>(argc, argv);
          }
          break;
        case 3:
          {
          AverageImages<3, 3>(argc, argv);
          }
          break;
        case 2:
          {
          AverageImages<3, 2>(argc, argv);
          }
          break;
        default:
          {
          AverageImages1<3, 1>(argc, argv);
          }
          break;
        }
      }
      break;
    case 4:
      {
      switch( ncomponents )
        {
        case 7:
          {
          AverageImages<4, 7>(argc, argv);
          }
          break;
        case 6:
          {
          AverageImages<4, 6>(argc, argv);
          }
          break;
        case 4:
          {
          AverageImages<4, 4>(argc, argv);
          }
          break;
        case 3:
          {
          AverageImages<4, 3>(argc, argv);
          }
          break;
        default:
          {
          AverageImages1<4, 1>(argc, argv);
          }
          break;
        }
      }
      break;
    default:
      std::cerr << " You passed ImageDimension: " << dim << " . Please use only image domains of 2, 3 or 4  "
                << std::endl;
      exit( EXIT_FAILURE );
    }

  return 0;
}
<commit_msg>BUG: ? possible bad behavior in an old averaging filter --- replacing with itk version <commit_after>/*=========================================================================

  Program:   Advanced Normalization Tools
  Module:    $RCSfile: AverageImages.cxx,v $
  Language:  C++
  Date:      $Date: 2009/01/27 23:25:24 $
  Version:   $Revision: 1.21 $

  Copyright (c) ConsortiumOfANTS. All rights reserved.
  See accompanying COPYING.txt or
 http://sourceforge.net/projects/advants/files/ANTS/ANTSCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// We divide the 2nd input image by its mean and add it to the first
// input image with weight 1/n.
// The output overwrites the 1st img with the sum.

// Note: could easily add variance computation
// http://people.revoledu.com/kardi/tutorial/RecursiveStatistic/Time-Variance.htm

#include "itkArray.h"
#include "itkVariableLengthVector.h"
#include "itkImage.h"
#include "itkImageRegionConstIterator.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIteratorWithIndex.h"
#include "itkOptimalSharpeningImageFilter.h"
#include "itkLaplacianSharpeningImageFilter.h"

template <unsigned int ImageDimension, unsigned int NVectorComponents>
int AverageImages1(unsigned int argc, char *argv[])
{
  typedef float                                        PixelType;
  typedef itk::Image<PixelType, ImageDimension>        ImageType;
  typedef itk::ImageRegionIteratorWithIndex<ImageType> Iterator;
  typedef itk::ImageFileReader<ImageType>              ImageFileReader;
  typedef itk::ImageFileWriter<ImageType>              writertype;

  bool  normalizei = atoi(argv[3]);
  float numberofimages = (float)argc - 4.;
  typename ImageType::Pointer averageimage = NULL;
  typename ImageType::Pointer image2 = NULL;

  typename ImageType::SizeType size;
  size.Fill(0);
  unsigned int bigimage = 0;
  for( unsigned int j = 4; j < argc; j++ )
    {
    // Get the image dimension
    std::string fn = std::string(argv[j]);
    std::cout << " fn " << fn << std::endl;
    typename itk::ImageIOBase::Pointer imageIO =
      itk::ImageIOFactory::CreateImageIO(fn.c_str(), itk::ImageIOFactory::ReadMode);
    imageIO->SetFileName(fn.c_str() );
    imageIO->ReadImageInformation();
    for( unsigned int i = 0; i < imageIO->GetNumberOfDimensions(); i++ )
      {
      if( imageIO->GetDimensions(i) > size[i] )
        {
        size[i] = imageIO->GetDimensions(i);
        bigimage = j;
        std::cout << " bigimage " << j << " size " << size << std::endl;
        }
      }
    }

  std::cout << " largest image " << size << std::endl;
  typename ImageFileReader::Pointer reader = ImageFileReader::New();
  reader->SetFileName(argv[bigimage]);
  reader->Update();
  averageimage = reader->GetOutput();
  unsigned int vectorlength = reader->GetImageIO()->GetNumberOfComponents();
  std::cout << " Averaging " << numberofimages << " images with dim = " << ImageDimension << " vector components "
            << vectorlength << std::endl;
  PixelType meanval = 0;
  averageimage->FillBuffer(meanval);
  for( unsigned int j = 4; j < argc; j++ )
    {
    std::cout << " reading " << std::string(argv[j]) << std::endl;
    typename ImageFileReader::Pointer reader = ImageFileReader::New();
    reader->SetFileName(argv[j]);
    reader->Update();
    image2 = reader->GetOutput();
    Iterator      vfIter2( image2,  image2->GetLargestPossibleRegion() );
    unsigned long ct = 0;
    if( normalizei )
      {
      meanval = 0;
      for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
        {
        PixelType localp = image2->GetPixel( vfIter2.GetIndex() );
        meanval = meanval + localp;
        ct++;
        }
      if( ct > 0 )
        {
        meanval = meanval / (float)ct;
        }
      if( meanval <= 0 )
        {
        meanval = (1);
        }
      }
    for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
      {
      PixelType val = vfIter2.Get();
      if( normalizei )
        {
        val /= meanval;
        }
      val = val / (float)numberofimages;
      PixelType oldval = averageimage->GetPixel(vfIter2.GetIndex() );
      averageimage->SetPixel(vfIter2.GetIndex(), val + oldval );
      }
    }

  //  typedef itk::OptimalSharpeningImageFilter<ImageType,ImageType > sharpeningFilter;
  typedef itk::LaplacianSharpeningImageFilter<ImageType, ImageType> sharpeningFilter;
  typename sharpeningFilter::Pointer shFilter = sharpeningFilter::New();
  if( normalizei && argc > 3 && vectorlength == 1 )
    {
    shFilter->SetInput( averageimage );
    //    shFilter->SetSValue(0.5);
    averageimage =  shFilter->GetOutput();
    }

  std::cout << " writing output ";
    {
    typename writertype::Pointer writer = writertype::New();
    writer->SetFileName(argv[2]);
    writer->SetInput( averageimage );
    writer->Update();
    }

  return 0;
}

template <unsigned int ImageDimension, unsigned int NVectorComponents>
int AverageImages(unsigned int argc, char *argv[])
{
  typedef itk::Vector<float, NVectorComponents>        PixelType;
  typedef itk::Image<PixelType, ImageDimension>        ImageType;
  typedef itk::ImageRegionIteratorWithIndex<ImageType> Iterator;
  typedef itk::ImageFileReader<ImageType>              ImageFileReader;
  typedef itk::ImageFileWriter<ImageType>              writertype;

  bool  normalizei = atoi(argv[3]);
  float numberofimages = (float)argc - 4.;
  typename ImageType::Pointer averageimage = NULL;
  typename ImageType::Pointer image2 = NULL;

  typename ImageType::SizeType size;
  size.Fill(0);
  unsigned int bigimage = 0;
  for( unsigned int j = 4; j < argc; j++ )
    {
    // Get the image dimension
    std::string fn = std::string(argv[j]);
    std::cout << " fn " << fn << std::endl;
    typename itk::ImageIOBase::Pointer imageIO =
      itk::ImageIOFactory::CreateImageIO(fn.c_str(), itk::ImageIOFactory::ReadMode);
    imageIO->SetFileName(fn.c_str() );
    imageIO->ReadImageInformation();
    for( unsigned int i = 0; i < imageIO->GetNumberOfDimensions(); i++ )
      {
      if( imageIO->GetDimensions(i) > size[i] )
        {
        size[i] = imageIO->GetDimensions(i);
        bigimage = j;
        std::cout << " bigimage " << j << " size " << size << std::endl;
        }
      }
    }

  std::cout << " largest image " << size << std::endl;
  typename ImageFileReader::Pointer reader = ImageFileReader::New();
  reader->SetFileName(argv[bigimage]);
  reader->Update();
  averageimage = reader->GetOutput();
  unsigned int vectorlength = reader->GetImageIO()->GetNumberOfComponents();
  std::cout << " Averaging " << numberofimages << " images with dim = " << ImageDimension << " vector components "
            << vectorlength << std::endl;
  typename ImageType::IndexType zindex; zindex.Fill(0);
  PixelType meanval = reader->GetOutput()->GetPixel(zindex);
  meanval.Fill(0);
  averageimage->FillBuffer(meanval);
  for( unsigned int j = 4; j < argc; j++ )
    {
    std::cout << " reading " << std::string(argv[j]) << std::endl;
    typename ImageFileReader::Pointer reader = ImageFileReader::New();
    reader->SetFileName(argv[j]);
    reader->Update();
    image2 = reader->GetOutput();
    Iterator      vfIter2( image2,  image2->GetLargestPossibleRegion() );
    unsigned long ct = 0;
    if( normalizei )
      {
      meanval.Fill(0);
      for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
        {
        PixelType localp = image2->GetPixel( vfIter2.GetIndex() );
        meanval = meanval + localp;
        ct++;
        }
      if( ct > 0 )
        {
        meanval = meanval / (float)ct;
        }
      if( meanval.GetNorm() <= 0 )
        {
        meanval.Fill(1);
        }
      }
    for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
      {
      PixelType val = vfIter2.Get();
      if( normalizei )
        {
        for( unsigned int k = 0; k < vectorlength; k++ )
          {
          val[k] /= meanval[k];
          }
        }
      val = val / (float)numberofimages;
      PixelType oldval = averageimage->GetPixel(vfIter2.GetIndex() );
      averageimage->SetPixel(vfIter2.GetIndex(), val + oldval );
      }
    }

    {
    typename writertype::Pointer writer = writertype::New();
    writer->SetFileName(argv[2]);
    writer->SetInput( averageimage );
    writer->Update();
    }

  return 0;
}

int main(int argc, char * argv[])
{
  if( argc < 3 )
    {
    std::cout << "\n" << std::endl;
    std::cout << "Usage: \n" << std::endl;
    std::cout << argv[0] << " ImageDimension Outputfname.nii.gz Normalize <images> \n" << std::endl;
    std::cout << " Compulsory arguments: \n" << std::endl;
    std::cout << " ImageDimension: 2 or 3 (for 2 or 3 dimensional input).\n " << std::endl;
    std::cout << " Outputfname.nii.gz: the name of the resulting image.\n" << std::endl;
    std::cout
      <<
    " Normalize: 0 (false) or 1 (true); if true, the 2nd image is divided by its mean. This will select the largest image to average into.\n"
      << std::endl;
    std::cout << " Example Usage:\n" << std::endl;
    std::cout << argv[0] << " 3 average.nii.gz  1  *.nii.gz \n" << std::endl;
    std::cout << " \n" << std::endl;
    return 1;
    }

  int                       dim = atoi( argv[1] );
  itk::ImageIOBase::Pointer imageIO =
    itk::ImageIOFactory::CreateImageIO(argv[4], itk::ImageIOFactory::ReadMode);
  imageIO->SetFileName(argv[4]);
  imageIO->ReadImageInformation();
  unsigned int ncomponents = imageIO->GetNumberOfComponents();

  // Get the image dimension
  switch( atoi(argv[1]) )
    {
    case 2:
      {
      switch( ncomponents )
        {
        case 2:
          {
          AverageImages<2, 2>(argc, argv);
          }
          break;
        default:
          {
          AverageImages1<2, 1>(argc, argv);
          }
          break;
        }
      }
      break;
    case 3:
      {
      switch( ncomponents )
        {
        case 7:
          {
          AverageImages<3, 7>(argc, argv);
          }
          break;
        case 6:
          {
          AverageImages<3, 6>(argc, argv);
          }
          break;
        case 3:
          {
          AverageImages<3, 3>(argc, argv);
          }
          break;
        case 2:
          {
          AverageImages<3, 2>(argc, argv);
          }
          break;
        default:
          {
          AverageImages1<3, 1>(argc, argv);
          }
          break;
        }
      }
      break;
    case 4:
      {
      switch( ncomponents )
        {
        case 7:
          {
          AverageImages<4, 7>(argc, argv);
          }
          break;
        case 6:
          {
          AverageImages<4, 6>(argc, argv);
          }
          break;
        case 4:
          {
          AverageImages<4, 4>(argc, argv);
          }
          break;
        case 3:
          {
          AverageImages<4, 3>(argc, argv);
          }
          break;
        default:
          {
          AverageImages1<4, 1>(argc, argv);
          }
          break;
        }
      }
      break;
    default:
      std::cerr << " You passed ImageDimension: " << dim << " . Please use only image domains of 2, 3 or 4  "
                << std::endl;
      exit( EXIT_FAILURE );
    }

  return 0;
}
<|endoftext|>


<commit_before>//
//  Effect.cpp
//  Audio Test
//
//  Created by Matthew Bucci on 2/6/14.
//  Copyright (c) 2014 Matthew Bucci. All rights reserved.
//

#include "Effect.h"

Effect::Effect() {
    Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 4096);
    cout << "Loading effects" << endl;
    load_files();
    event test;
    test.type="ui-newability";
    test.id=5;
    PlayEffect(test);
}

void Effect::PlayEffect(event action) {
    if(action.type=="player-walk"){
        if(foot)
            Mix_PlayChannel(-1,effects["player-left-foot"],0);
        else
            Mix_PlayChannel(-1,effects["player-right-foot"],0);
    }
    else {
        Mix_PlayChannel(-1,effects[action.type],0);
    }
}

bool Effect::load_files() {
    //Load the music
    fstream File("sounds/Effects.txt");
    string tmp;
    //Effect File Defintion Format
        //EffectName pathtofile
    while(File) {
        //super ineffecient but garuntees broken lines won't mess up the rest
        getline(File,tmp);
        stringstream ss(tmp);
        vector<string> params;

        while (ss >> tmp) {
            params.push_back(tmp);
        }

        //ignore comment lines
        if(params.size() == 2) {
            if(params[0].substr(0,2) != "//") {
                cout << "Loaded: " << params[0]<< endl;
                effects.insert ( pair<string,Mix_Chunk*>(params[0],Mix_LoadWAV(params[1].c_str())) );
            }
        }
        params.clear();
    }
    File.close();

    return true;
}

void Effect::SetVolume(uint8_t volume) {
    this->volume = volume;

    //sets unallocated channels to new volume
    Mix_Volume(-1, volume);

    //need to add a loop to adjust allocated channels
}<commit_msg>now android can play with the big boys<commit_after>//
//  Effect.cpp
//  Audio Test
//
//  Created by Matthew Bucci on 2/6/14.
//  Copyright (c) 2014 Matthew Bucci. All rights reserved.
//

#include "Effect.h"

Effect::Effect() {
    Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 4096);
    cout << "Loading effects" << endl;
    load_files();
    event test;
    test.type="ui-newability";
    test.id=5;
    PlayEffect(test);
}

void Effect::PlayEffect(event action) {
    if(action.type=="player-walk"){
        if(foot)
            Mix_PlayChannel(-1,effects["player-left-foot"],0);
        else
            Mix_PlayChannel(-1,effects["player-right-foot"],0);
    }
    else {
        Mix_PlayChannel(-1,effects[action.type],0);
    }
}

void ReadFiles(string data, map<string,Mix_Chunk*>& effects) {

}
bool Effect::load_files() {
    //Load the effects
    string filename = "sounds/Effects.txt";

	SDL_RWops *file = SDL_RWFromFile(filename.c_str(), "r");
	long size;

	cout << "Parsing particle file \"" << filename << "\":";

	if(!file) {
		cout << "\nFailed to open particle data file \"" << filename << "\"\n";
		return NULL;
	}

	//Use the SDL system to read the file
	SDL_RWseek(file , 0 , RW_SEEK_END);
	size = (long)SDL_RWtell(file);
	SDL_RWseek(file,0,RW_SEEK_SET);

	char * fileData = new char[size];
	SDL_RWread(file,fileData, 1, (size_t)size);
	SDL_RWclose(file);

    stringstream File(string(fileData,size));

    string tmp;
    //Effect File Defintion Format
        //EffectName pathtofile
    while(File) {
        //super ineffecient but garuntees broken lines won't mess up the rest
        getline(File,tmp);
        stringstream ss(tmp);
        vector<string> params;

        while (ss >> tmp) {
            params.push_back(tmp);
        }

        //ignore comment lines
        if(params.size() == 2) {
            if(params[0].substr(0,2) != "//") {
                cout << "Loaded: " << params[0]<< endl;
                effects.insert ( pair<string,Mix_Chunk*>(params[0],Mix_LoadWAV(params[1].c_str())) );
            }
        }
        params.clear();
    }

    return true;
}

void Effect::SetVolume(uint8_t volume) {
    this->volume = volume;

    //sets unallocated channels to new volume
    Mix_Volume(-1, volume);

    //need to add a loop to adjust allocated channels
}<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* libmspub
 * Version: MPL 1.1 / GPLv2+ / LGPLv2+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License or as specified alternatively below. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Major Contributor(s):
 * Copyright (C) 2012 Fridrich Strba <fridrich.strba@bluewin.ch>
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
 * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
 * instead of those above.
 */

#include <sstream>
#include <string>
#include <string.h>
#include <libwpd-stream/WPXStream.h>
#include "MSPUBParser.h"
#include "MSPUBCollector.h"
#include "libmspub_utils.h"

libmspub::MSPUBParser::MSPUBParser(WPXInputStream *input, MSPUBCollector *collector)
  : m_input(input), m_collector(collector), m_blockInfo(), m_lastSeenSeqNum(-1)
{
}

libmspub::MSPUBParser::~MSPUBParser()
{
}

short libmspub::MSPUBParser::getBlockDataLength(unsigned type) // -1 for variable-length block with the data length as the first DWORD
{
  switch(type)
  {
  case 0x78:
  case 0x5:
  case 0x8:
  case 0xa:
    return 0;
  case 0x10:
  case 0x12:
  case 0x18:
  case 0x1a:
    return 2;
  case 0x20:
  case 0x22:
  case 0x28:
  case 0x48:
  case 0x58:
  case 0x68:
  case 0x70:
  case 0xb8:
    return 4;
  case 0x38:
    return 16;
  case 0xc0:
  case 0x80:
  case 0x82:
  case 0x88:
  case 0x8a:
  case 0x90:
  case 0x98:
  case 0xa0:
    return -1;
  }
  //FIXME: Debug assertion here? Should never get here.
  return 0;
}

bool libmspub::MSPUBParser::parse()
{
  if (!m_input->isOLEStream())
    return false;
  WPXInputStream *quill = m_input->getDocumentOLEStream("Quill/QuillSub/CONTENTS");
  if (!quill)
    return false;
  if (!parseQuill(quill))
  {
    delete quill;
    return false;
  }
  delete quill;
  WPXInputStream *escher = m_input->getDocumentOLEStream("Escher/EscherStm");
  if (!escher)
    return false;
  if (!parseEscher(escher))
  {
    delete escher;
    return false;
  }
  delete escher;
  WPXInputStream *contents = m_input->getDocumentOLEStream("Contents");
  if (!contents)
    return false;
  if (!parseContents(contents))
  {
    delete contents;
    return false;
  }
  delete contents;
  return true;
}

bool libmspub::MSPUBParser::parseContents(WPXInputStream *input)
{
  MSPUB_DEBUG_MSG(("MSPUBParser::parseContents\n"));
  input->seek(0x1a, WPX_SEEK_SET);

  unsigned trailerOffset = readU32(input);
  MSPUB_DEBUG_MSG(("MSPUBParser: trailerOffset %.8x\n", trailerOffset));
  input->seek(trailerOffset, WPX_SEEK_SET);
  unsigned trailerLength = readU32(input);
  for (unsigned i=0; i<3; i++)
  {
    libmspub::MSPUBBlockInfo trailerPart = parseBlock(input);
    MSPUB_DEBUG_MSG(("Trailer SubBlock %i, startPosition 0x%lx, id %i, type 0x%x, dataLength 0x%lx\n", i+1, trailerPart.startPosition, trailerPart.id, trailerPart.type, trailerPart.dataLength));
    if (trailerPart.type == 0x90)
    {
      while (input->tell() >= 0 && (unsigned)input->tell() < trailerPart.dataOffset + trailerPart.dataLength)
      {
        m_blockInfo.push_back(parseBlock(input));
        ++m_lastSeenSeqNum;
        if (m_blockInfo.back().type == 0x88)
        {
          parseChunkReference(input, m_blockInfo.back());
        }
      }
      for (MSPUBCollector::cr_iterator_t i = m_collector->getChunkReferences().begin(); i != m_collector->getChunkReferences().end(); ++i)
      {
        if (i->type == 0x44)
        {
          input->seek(i->offset, WPX_SEEK_SET);
          if (!parseDocumentChunk(input, *i))
          {
            return false;
          }
        }
        else if (i->type == 0x43)
        {
          input->seek(i->offset, WPX_SEEK_SET);
          if (!parsePageChunk(input, *i))
          {
            return false;
          }
        }
      }
      m_collector->pagesOver();
    }
  }
  input->seek(trailerOffset + trailerLength, WPX_SEEK_SET);

  return true;
}

bool libmspub::MSPUBParser::parseDocumentChunk(WPXInputStream *input, const ChunkReference &chunk)
{
  readU32(input); //FIXME: This is the length. Might want to verify that it matches the length we got from subtracting the start of this chunk from the start of the next one.
  while (input->tell() >= 0 && (unsigned)input->tell() < chunk.end)
  {
    libmspub::MSPUBBlockInfo info = parseBlock(input);
    if (info.id == 0x12)
    {
      while (input->tell() >= 0 && (unsigned)input->tell() < info.dataOffset + info.dataLength)
      {
        libmspub::MSPUBBlockInfo subInfo = parseBlock(input, true);
        if (subInfo.id == 0x1)
        {
          m_collector->setWidthInEmu(subInfo.data);
        }
        else if (subInfo.id == 0x2)
        {
          m_collector->setHeightInEmu(subInfo.data);
        }
      }
    }
    else
    {
      skipBlock(input, info);
    }
  }
  return true; //FIXME: return false for failure
}

bool libmspub::MSPUBParser::parsePageChunk(WPXInputStream *input, const ChunkReference &chunk)
{
  MSPUB_DEBUG_MSG(("parsePageChunk: offset 0x%lx, end 0x%lx, seqnum 0x%x, parent 0x%x\n", input->tell(), chunk.end, chunk.seqNum, chunk.parentSeqNum));
  if (getPageTypeBySeqNum(chunk.seqNum) == NORMAL)
  {
    m_collector->addPage();
  }
  return true;
}

bool libmspub::MSPUBParser::parseQuill(WPXInputStream *input)
{
  MSPUB_DEBUG_MSG(("MSPUBParser::parseQuill\n"));
  return true;
}

bool libmspub::MSPUBParser::parseEscher(WPXInputStream *input)
{
  MSPUB_DEBUG_MSG(("MSPUBParser::parseEscher\n"));
  return true;
}

bool libmspub::MSPUBParser::parseChunkReference(WPXInputStream *input, const libmspub::MSPUBBlockInfo block)
{
  //input should be at block.dataOffset + 4 , that is, at the beginning of the list of sub-blocks
  unsigned type = 0;
  unsigned long offset = 0;
  unsigned parentSeqNum = 0;
  bool seenType = false;
  bool seenOffset = false;
  bool seenParentSeqNum = false;
  while (input->tell() >= 0 && (unsigned)input->tell() < block.dataOffset + block.dataLength)
  {
    libmspub::MSPUBBlockInfo subBlock = parseBlock(input);
    //FIXME: Warn if multiple of these blocks seen.
    if (subBlock.id == 0x2)
    {
      type = (unsigned)subBlock.data;
      seenType = true;
    }
    else if (subBlock.id == 0x4)
    {
      offset = subBlock.data;
      seenOffset = true;
    }
    else if (subBlock.id == 0x5)
    {
      parentSeqNum = subBlock.data;
      seenParentSeqNum = true;
    }
  }
  if (seenType && seenOffset)
  {
    m_collector->addChunkReference(type, offset, m_lastSeenSeqNum, seenParentSeqNum ? parentSeqNum : 0);
    return true;
  }
  return false;
}

bool libmspub::MSPUBParser::isBlockDataString(unsigned type)
{
  return type == 0xc0;
}
void libmspub::MSPUBParser::skipBlock(WPXInputStream *input, libmspub::MSPUBBlockInfo block)
{
  input->seek(block.dataOffset + block.dataLength, WPX_SEEK_SET);
}
libmspub::MSPUBBlockInfo libmspub::MSPUBParser::parseBlock(WPXInputStream *input, bool skipHierarchicalData)
{
  libmspub::MSPUBBlockInfo info;
  info.startPosition = input->tell();
  info.id = readU8(input);
  info.type = readU8(input);
  info.dataOffset = input->tell();
  int len = getBlockDataLength(info.type);
  bool varLen = len < 0;
  if (varLen)
  {
    info.dataLength = readU32(input);
    if (isBlockDataString(info.type))
    {
      info.stringData = std::vector<char>(info.dataLength - 1);
      for (unsigned i = 0; i < info.dataLength - 1; ++i)
      {
        info.stringData[i] = readU8(input);
      }
    }
    else if (skipHierarchicalData)
    {
      skipBlock(input, info);
    }
    info.data = 0;
  }
  else
  {
    info.dataLength = len;
    switch (info.dataLength)
    {
    case 1:
      info.data = readU8(input);
      break;
    case 2:
      info.data = readU16(input);
      break;
    case 4:
      info.data = readU32(input);
      break;
    default:
      info.data = 0;
    }
  }
  MSPUB_DEBUG_MSG(("parseBlock dataOffset 0x%lx, id 0x%x, type 0x%x, dataLength %lu, integral data 0x%lx\n", info.dataOffset, info.id, info.type, info.dataLength, info.data));
  return info;
}

libmspub::PageType libmspub::MSPUBParser::getPageTypeBySeqNum(unsigned seqNum)
{
  switch(seqNum)
  {
  case 0x107:
    return MASTER;
  case 0x10d:
  case 0x110:
  case 0x113:
  case 0x117:
    return DUMMY;
  default:
    return NORMAL;
  }
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<commit_msg>Valek knows more about 0x48<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* libmspub
 * Version: MPL 1.1 / GPLv2+ / LGPLv2+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License or as specified alternatively below. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Major Contributor(s):
 * Copyright (C) 2012 Fridrich Strba <fridrich.strba@bluewin.ch>
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
 * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
 * instead of those above.
 */

#include <sstream>
#include <string>
#include <string.h>
#include <libwpd-stream/WPXStream.h>
#include "MSPUBParser.h"
#include "MSPUBCollector.h"
#include "libmspub_utils.h"

libmspub::MSPUBParser::MSPUBParser(WPXInputStream *input, MSPUBCollector *collector)
  : m_input(input), m_collector(collector), m_blockInfo(), m_lastSeenSeqNum(-1)
{
}

libmspub::MSPUBParser::~MSPUBParser()
{
}

short libmspub::MSPUBParser::getBlockDataLength(unsigned type) // -1 for variable-length block with the data length as the first DWORD
{
  switch(type)
  {
  case 0x78:
  case 0x5:
  case 0x8:
  case 0xa:
    return 0;
  case 0x10:
  case 0x12:
  case 0x18:
  case 0x1a:
    return 2;
  case 0x20:
  case 0x22:
  case 0x28:
  case 0x58:
  case 0x68:
  case 0x70:
  case 0xb8:
    return 4;
  case 0x38:
    return 16;
  case 0x48:
    return 24;
  case 0xc0:
  case 0x80:
  case 0x82:
  case 0x88:
  case 0x8a:
  case 0x90:
  case 0x98:
  case 0xa0:
    return -1;
  }
  //FIXME: Debug assertion here? Should never get here.
  return 0;
}

bool libmspub::MSPUBParser::parse()
{
  if (!m_input->isOLEStream())
    return false;
  WPXInputStream *quill = m_input->getDocumentOLEStream("Quill/QuillSub/CONTENTS");
  if (!quill)
    return false;
  if (!parseQuill(quill))
  {
    delete quill;
    return false;
  }
  delete quill;
  WPXInputStream *escher = m_input->getDocumentOLEStream("Escher/EscherStm");
  if (!escher)
    return false;
  if (!parseEscher(escher))
  {
    delete escher;
    return false;
  }
  delete escher;
  WPXInputStream *contents = m_input->getDocumentOLEStream("Contents");
  if (!contents)
    return false;
  if (!parseContents(contents))
  {
    delete contents;
    return false;
  }
  delete contents;
  return true;
}

bool libmspub::MSPUBParser::parseContents(WPXInputStream *input)
{
  MSPUB_DEBUG_MSG(("MSPUBParser::parseContents\n"));
  input->seek(0x1a, WPX_SEEK_SET);

  unsigned trailerOffset = readU32(input);
  MSPUB_DEBUG_MSG(("MSPUBParser: trailerOffset %.8x\n", trailerOffset));
  input->seek(trailerOffset, WPX_SEEK_SET);
  unsigned trailerLength = readU32(input);
  for (unsigned i=0; i<3; i++)
  {
    libmspub::MSPUBBlockInfo trailerPart = parseBlock(input);
    MSPUB_DEBUG_MSG(("Trailer SubBlock %i, startPosition 0x%lx, id %i, type 0x%x, dataLength 0x%lx\n", i+1, trailerPart.startPosition, trailerPart.id, trailerPart.type, trailerPart.dataLength));
    if (trailerPart.type == 0x90)
    {
      while (input->tell() >= 0 && (unsigned)input->tell() < trailerPart.dataOffset + trailerPart.dataLength)
      {
        m_blockInfo.push_back(parseBlock(input));
        ++m_lastSeenSeqNum;
        if (m_blockInfo.back().type == 0x88)
        {
          parseChunkReference(input, m_blockInfo.back());
        }
      }
      for (MSPUBCollector::cr_iterator_t i = m_collector->getChunkReferences().begin(); i != m_collector->getChunkReferences().end(); ++i)
      {
        if (i->type == 0x44)
        {
          input->seek(i->offset, WPX_SEEK_SET);
          if (!parseDocumentChunk(input, *i))
          {
            return false;
          }
        }
        else if (i->type == 0x43)
        {
          input->seek(i->offset, WPX_SEEK_SET);
          if (!parsePageChunk(input, *i))
          {
            return false;
          }
        }
      }
      m_collector->pagesOver();
    }
  }
  input->seek(trailerOffset + trailerLength, WPX_SEEK_SET);

  return true;
}

bool libmspub::MSPUBParser::parseDocumentChunk(WPXInputStream *input, const ChunkReference &chunk)
{
  readU32(input); //FIXME: This is the length. Might want to verify that it matches the length we got from subtracting the start of this chunk from the start of the next one.
  while (input->tell() >= 0 && (unsigned)input->tell() < chunk.end)
  {
    libmspub::MSPUBBlockInfo info = parseBlock(input);
    if (info.id == 0x12)
    {
      while (input->tell() >= 0 && (unsigned)input->tell() < info.dataOffset + info.dataLength)
      {
        libmspub::MSPUBBlockInfo subInfo = parseBlock(input, true);
        if (subInfo.id == 0x1)
        {
          m_collector->setWidthInEmu(subInfo.data);
        }
        else if (subInfo.id == 0x2)
        {
          m_collector->setHeightInEmu(subInfo.data);
        }
      }
    }
    else
    {
      skipBlock(input, info);
    }
  }
  return true; //FIXME: return false for failure
}

bool libmspub::MSPUBParser::parsePageChunk(WPXInputStream *input, const ChunkReference &chunk)
{
  MSPUB_DEBUG_MSG(("parsePageChunk: offset 0x%lx, end 0x%lx, seqnum 0x%x, parent 0x%x\n", input->tell(), chunk.end, chunk.seqNum, chunk.parentSeqNum));
  if (getPageTypeBySeqNum(chunk.seqNum) == NORMAL)
  {
    m_collector->addPage();
  }
  return true;
}

bool libmspub::MSPUBParser::parseQuill(WPXInputStream *input)
{
  MSPUB_DEBUG_MSG(("MSPUBParser::parseQuill\n"));
  return true;
}

bool libmspub::MSPUBParser::parseEscher(WPXInputStream *input)
{
  MSPUB_DEBUG_MSG(("MSPUBParser::parseEscher\n"));
  return true;
}

bool libmspub::MSPUBParser::parseChunkReference(WPXInputStream *input, const libmspub::MSPUBBlockInfo block)
{
  //input should be at block.dataOffset + 4 , that is, at the beginning of the list of sub-blocks
  unsigned type = 0;
  unsigned long offset = 0;
  unsigned parentSeqNum = 0;
  bool seenType = false;
  bool seenOffset = false;
  bool seenParentSeqNum = false;
  while (input->tell() >= 0 && (unsigned)input->tell() < block.dataOffset + block.dataLength)
  {
    libmspub::MSPUBBlockInfo subBlock = parseBlock(input);
    //FIXME: Warn if multiple of these blocks seen.
    if (subBlock.id == 0x2)
    {
      type = (unsigned)subBlock.data;
      seenType = true;
    }
    else if (subBlock.id == 0x4)
    {
      offset = subBlock.data;
      seenOffset = true;
    }
    else if (subBlock.id == 0x5)
    {
      parentSeqNum = subBlock.data;
      seenParentSeqNum = true;
    }
  }
  if (seenType && seenOffset)
  {
    m_collector->addChunkReference(type, offset, m_lastSeenSeqNum, seenParentSeqNum ? parentSeqNum : 0);
    return true;
  }
  return false;
}

bool libmspub::MSPUBParser::isBlockDataString(unsigned type)
{
  return type == 0xc0;
}
void libmspub::MSPUBParser::skipBlock(WPXInputStream *input, libmspub::MSPUBBlockInfo block)
{
  input->seek(block.dataOffset + block.dataLength, WPX_SEEK_SET);
}
libmspub::MSPUBBlockInfo libmspub::MSPUBParser::parseBlock(WPXInputStream *input, bool skipHierarchicalData)
{
  libmspub::MSPUBBlockInfo info;
  info.startPosition = input->tell();
  info.id = readU8(input);
  info.type = readU8(input);
  info.dataOffset = input->tell();
  int len = getBlockDataLength(info.type);
  bool varLen = len < 0;
  if (varLen)
  {
    info.dataLength = readU32(input);
    if (isBlockDataString(info.type))
    {
      info.stringData = std::vector<char>(info.dataLength - 1);
      for (unsigned i = 0; i < info.dataLength - 1; ++i)
      {
        info.stringData[i] = readU8(input);
      }
    }
    else if (skipHierarchicalData)
    {
      skipBlock(input, info);
    }
    info.data = 0;
  }
  else
  {
    info.dataLength = len;
    switch (info.dataLength)
    {
    case 1:
      info.data = readU8(input);
      break;
    case 2:
      info.data = readU16(input);
      break;
    case 4:
      info.data = readU32(input);
      break;
    default:
      info.data = 0;
    }
  }
  MSPUB_DEBUG_MSG(("parseBlock dataOffset 0x%lx, id 0x%x, type 0x%x, dataLength %lu, integral data 0x%lx\n", info.dataOffset, info.id, info.type, info.dataLength, info.data));
  return info;
}

libmspub::PageType libmspub::MSPUBParser::getPageTypeBySeqNum(unsigned seqNum)
{
  switch(seqNum)
  {
  case 0x107:
    return MASTER;
  case 0x10d:
  case 0x110:
  case 0x113:
  case 0x117:
    return DUMMY;
  default:
    return NORMAL;
  }
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<|endoftext|>


<commit_before>/*
* (C) 2015,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ffi.h>
#include <botan/internal/ffi_util.h>
#include <botan/internal/ffi_rng.h>
#include <botan/pbkdf.h>
#include <botan/kdf.h>

#if defined(BOTAN_HAS_BCRYPT)
  #include <botan/bcrypt.h>
#endif

#if defined(BOTAN_HAS_SCRYPT)
  #include <botan/scrypt.h>
#endif

extern "C" {

using namespace Botan_FFI;

int botan_pbkdf(const char* algo, uint8_t out[], size_t out_len,
                const char* pass, const uint8_t salt[], size_t salt_len,
                size_t iterations)
   {
   return botan_pwdhash(algo,
                        iterations,
                        0,
                        0,
                        out, out_len,
                        pass, 0,
                        salt, salt_len);
   }

int botan_pbkdf_timed(const char* algo,
                      uint8_t out[], size_t out_len,
                      const char* password,
                      const uint8_t salt[], size_t salt_len,
                      size_t ms_to_run,
                      size_t* iterations_used)
   {
   return botan_pwdhash_timed(algo,
                              static_cast<uint32_t>(ms_to_run),
                              iterations_used,
                              nullptr,
                              nullptr,
                              out, out_len,
                              password, 0,
                              salt, salt_len);
   }

int botan_pwdhash(
   const char* algo,
   size_t param1,
   size_t param2,
   size_t param3,
   uint8_t out[],
   size_t out_len,
   const char* password,
   size_t password_len,
   const uint8_t salt[],
   size_t salt_len)
   {
   if(algo == nullptr || password == nullptr)
      return BOTAN_FFI_ERROR_NULL_POINTER;

   if(password_len == 0)
      password_len = std::strlen(password);

   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      auto pwdhash_fam = Botan::PasswordHashFamily::create(algo);

      if(!pwdhash_fam)
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;

      auto pwdhash = pwdhash_fam->from_params(param1, param2, param3);

      pwdhash->derive_key(out, out_len,
                          password, password_len,
                          salt, salt_len);

      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pwdhash_timed(
   const char* algo,
   uint32_t msec,
   size_t* param1,
   size_t* param2,
   size_t* param3,
   uint8_t out[],
   size_t out_len,
   const char* password,
   size_t password_len,
   const uint8_t salt[],
   size_t salt_len)
   {
   if(algo == nullptr || password == nullptr)
      return BOTAN_FFI_ERROR_NULL_POINTER;

   if(password_len == 0)
      password_len = std::strlen(password);

   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {

      auto pwdhash_fam = Botan::PasswordHashFamily::create(algo);

      if(!pwdhash_fam)
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;

      auto pwdhash = pwdhash_fam->tune(out_len, std::chrono::milliseconds(msec));

      if(param1)
         *param1 = pwdhash->iterations();
      if(param2)
         *param2 = pwdhash->parallelism();
      if(param3)
         *param3 = pwdhash->memory_param();

      pwdhash->derive_key(out, out_len,
                          password, password_len,
                          salt, salt_len);

      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_kdf(const char* kdf_algo,
              uint8_t out[], size_t out_len,
              const uint8_t secret[], size_t secret_len,
              const uint8_t salt[], size_t salt_len,
              const uint8_t label[], size_t label_len)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      std::unique_ptr<Botan::KDF> kdf(Botan::get_kdf(kdf_algo));
      kdf->kdf(out, out_len, secret, secret_len, salt, salt_len, label, label_len);
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_scrypt(uint8_t out[], size_t out_len,
                 const char* password,
                 const uint8_t salt[], size_t salt_len,
                 size_t N, size_t r, size_t p)
   {
#if defined(BOTAN_HAS_SCRYPT)
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      Botan::scrypt(out, out_len, password, strlen(password), salt, salt_len, N, r, p);
      return BOTAN_FFI_SUCCESS;
   });
#else
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

int botan_bcrypt_generate(uint8_t* out, size_t* out_len,
                          const char* pass,
                          botan_rng_t rng_obj, size_t wf,
                          uint32_t flags)
   {
#if defined(BOTAN_HAS_BCRYPT)
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      if(out == nullptr || out_len == nullptr || pass == nullptr)
         return BOTAN_FFI_ERROR_NULL_POINTER;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      if(wf < 4 || wf > 18)
         return BOTAN_FFI_ERROR_BAD_PARAMETER;

      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
      const std::string bcrypt = Botan::generate_bcrypt(pass, rng, static_cast<uint16_t>(wf));
      return write_str_output(out, out_len, bcrypt);
      });
#else
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

int botan_bcrypt_is_valid(const char* pass, const char* hash)
   {
#if defined(BOTAN_HAS_BCRYPT)
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      return Botan::check_bcrypt(pass, hash) ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER;
      });
#else
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

}
<commit_msg>Define botan_scrypt in terms of botan_pwdhash<commit_after>/*
* (C) 2015,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ffi.h>
#include <botan/internal/ffi_util.h>
#include <botan/internal/ffi_rng.h>
#include <botan/pbkdf.h>
#include <botan/pwdhash.h>
#include <botan/kdf.h>

#if defined(BOTAN_HAS_BCRYPT)
  #include <botan/bcrypt.h>
#endif

extern "C" {

using namespace Botan_FFI;

int botan_pbkdf(const char* algo, uint8_t out[], size_t out_len,
                const char* pass, const uint8_t salt[], size_t salt_len,
                size_t iterations)
   {
   return botan_pwdhash(algo,
                        iterations,
                        0,
                        0,
                        out, out_len,
                        pass, 0,
                        salt, salt_len);
   }

int botan_pbkdf_timed(const char* algo,
                      uint8_t out[], size_t out_len,
                      const char* password,
                      const uint8_t salt[], size_t salt_len,
                      size_t ms_to_run,
                      size_t* iterations_used)
   {
   return botan_pwdhash_timed(algo,
                              static_cast<uint32_t>(ms_to_run),
                              iterations_used,
                              nullptr,
                              nullptr,
                              out, out_len,
                              password, 0,
                              salt, salt_len);
   }

int botan_pwdhash(
   const char* algo,
   size_t param1,
   size_t param2,
   size_t param3,
   uint8_t out[],
   size_t out_len,
   const char* password,
   size_t password_len,
   const uint8_t salt[],
   size_t salt_len)
   {
   if(algo == nullptr || password == nullptr)
      return BOTAN_FFI_ERROR_NULL_POINTER;

   if(password_len == 0)
      password_len = std::strlen(password);

   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      auto pwdhash_fam = Botan::PasswordHashFamily::create(algo);

      if(!pwdhash_fam)
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;

      auto pwdhash = pwdhash_fam->from_params(param1, param2, param3);

      pwdhash->derive_key(out, out_len,
                          password, password_len,
                          salt, salt_len);

      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pwdhash_timed(
   const char* algo,
   uint32_t msec,
   size_t* param1,
   size_t* param2,
   size_t* param3,
   uint8_t out[],
   size_t out_len,
   const char* password,
   size_t password_len,
   const uint8_t salt[],
   size_t salt_len)
   {
   if(algo == nullptr || password == nullptr)
      return BOTAN_FFI_ERROR_NULL_POINTER;

   if(password_len == 0)
      password_len = std::strlen(password);

   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {

      auto pwdhash_fam = Botan::PasswordHashFamily::create(algo);

      if(!pwdhash_fam)
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;

      auto pwdhash = pwdhash_fam->tune(out_len, std::chrono::milliseconds(msec));

      if(param1)
         *param1 = pwdhash->iterations();
      if(param2)
         *param2 = pwdhash->parallelism();
      if(param3)
         *param3 = pwdhash->memory_param();

      pwdhash->derive_key(out, out_len,
                          password, password_len,
                          salt, salt_len);

      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_kdf(const char* kdf_algo,
              uint8_t out[], size_t out_len,
              const uint8_t secret[], size_t secret_len,
              const uint8_t salt[], size_t salt_len,
              const uint8_t label[], size_t label_len)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      std::unique_ptr<Botan::KDF> kdf(Botan::get_kdf(kdf_algo));
      kdf->kdf(out, out_len, secret, secret_len, salt, salt_len, label, label_len);
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_scrypt(uint8_t out[], size_t out_len,
                 const char* password,
                 const uint8_t salt[], size_t salt_len,
                 size_t N, size_t r, size_t p)
   {
   return botan_pwdhash("Scrypt", N, r, p,
                        out, out_len,
                        password, 0,
                        salt, salt_len);
   }

int botan_bcrypt_generate(uint8_t* out, size_t* out_len,
                          const char* pass,
                          botan_rng_t rng_obj, size_t wf,
                          uint32_t flags)
   {
#if defined(BOTAN_HAS_BCRYPT)
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      if(out == nullptr || out_len == nullptr || pass == nullptr)
         return BOTAN_FFI_ERROR_NULL_POINTER;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      if(wf < 4 || wf > 18)
         return BOTAN_FFI_ERROR_BAD_PARAMETER;

      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
      const std::string bcrypt = Botan::generate_bcrypt(pass, rng, static_cast<uint16_t>(wf));
      return write_str_output(out, out_len, bcrypt);
      });
#else
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

int botan_bcrypt_is_valid(const char* pass, const char* hash)
   {
#if defined(BOTAN_HAS_BCRYPT)
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      return Botan::check_bcrypt(pass, hash) ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER;
      });
#else
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
   }

}
<|endoftext|>


<commit_before>/*
 * Configuration.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_LB_CONFIG_H
#define BENG_LB_CONFIG_H

#include "address_list.hxx"
#include "sticky.h"
#include "ssl_config.hxx"
#include "net/AllocatedSocketAddress.hxx"

#include <http/status.h>

#include <glib.h>

#include <map>
#include <list>
#include <vector>
#include <string>

struct pool;

enum lb_protocol {
    LB_PROTOCOL_HTTP,
    LB_PROTOCOL_TCP,
};

struct lb_control_config {
    AllocatedSocketAddress bind_address;
};

struct lb_monitor_config {
    std::string name;

    /**
     * Time in seconds between two monitor checks.
     */
    unsigned interval;

    /**
     * If the monitor does not produce a result after this timeout
     * [seconds], it is assumed to be negative.
     */
    unsigned timeout;

    enum class Type {
        NONE,
        PING,
        CONNECT,
        TCP_EXPECT,
    } type;

    /**
     * The timeout for establishing a connection.  Only applicable for
     * #Type::TCP_EXPECT.  0 means no special setting present.
     */
    unsigned connect_timeout;

    /**
     * For #Type::TCP_EXPECT: a string that is sent to the peer
     * after the connection has been established.  May be empty.
     */
    std::string send;

    /**
     * For #Type::TCP_EXPECT: a string that is expected to be
     * received from the peer after the #send string has been sent.
     */
    std::string expect;

    /**
     * For #Type::TCP_EXPECT: if that string is received from the
     * peer (instead of #expect), then the node is assumed to be
     * shutting down gracefully, and will only get sticky requests.
     */
    std::string fade_expect;

    lb_monitor_config(const char *_name)
        :name(_name),
         interval(10), timeout(0),
         type(Type::NONE),
         connect_timeout(0) {}
};

struct lb_node_config {
    std::string name;

    AllocatedSocketAddress address;

    /**
     * The Tomcat "jvmRoute" setting of this node.  It is used for
     * #STICKY_JVM_ROUTE.
     */
    std::string jvm_route;

    lb_node_config(const char *_name)
        :name(_name) {}

    lb_node_config(const char *_name, AllocatedSocketAddress &&_address)
        :name(_name), address(std::move(_address)) {}

    lb_node_config(lb_node_config &&src)
        :name(std::move(src.name)), address(std::move(src.address)),
         jvm_route(std::move(src.jvm_route)) {}
};

struct lb_member_config {
    const struct lb_node_config *node;

    unsigned port;

    lb_member_config():node(nullptr), port(0) {}
};

struct lb_fallback_config {
    http_status_t status;

    /**
     * The "Location" response header.
     */
    std::string location;

    std::string message;

    bool IsDefined() const {
        return !location.empty() || !message.empty();
    }
};

struct lb_cluster_config {
    std::string name;

    /**
     * The protocol that is spoken on this cluster.
     */
    enum lb_protocol protocol;

    /**
     * Use the client's source IP for the connection to the backend?
     * This is implemented using IP_TRANSPARENT and requires the
     * "tproxy" Linux kernel module.
     */
    bool transparent_source;

    bool mangle_via;

    struct lb_fallback_config fallback;

    enum sticky_mode sticky_mode;

    std::string session_cookie;

    const struct lb_monitor_config *monitor;

    std::vector<lb_member_config> members;

    /**
     * A list of node addresses.
     */
    AddressList address_list;

    lb_cluster_config(const char *_name)
        :name(_name),
         protocol(LB_PROTOCOL_HTTP),
         transparent_source(false),
         mangle_via(false),
         sticky_mode(STICKY_NONE),
         session_cookie("beng_proxy_session"),
         monitor(nullptr) {}

    /**
     * Returns the member index of the node with the specified
     * jvm_route value, or -1 if not found.
     */
    gcc_pure
    int FindJVMRoute(const char *jvm_route) const;
};

struct lb_attribute_reference {
    enum class Type {
        METHOD,
        URI,
        HEADER,
    } type;

    std::string name;

    template<typename N>
    lb_attribute_reference(Type _type, N &&_name)
        :type(_type), name(std::forward<N>(_name)) {}
};

struct lb_branch_config;

struct lb_goto {
    const lb_cluster_config *cluster;
    const lb_branch_config *branch;

    lb_goto()
        :cluster(nullptr), branch(nullptr) {}

    lb_goto(lb_cluster_config *_cluster)
        :cluster(_cluster), branch(nullptr) {}

    lb_goto(lb_branch_config *_branch)
        :cluster(nullptr), branch(_branch) {}

    bool IsDefined() const {
        return cluster != nullptr || branch != nullptr;
    }

    gcc_pure
    lb_protocol GetProtocol() const;

    gcc_pure
    const char *GetName() const;
};

struct lb_condition_config {
    lb_attribute_reference attribute_reference;

    enum class Operator {
        EQUALS,
        REGEX,
    };

    Operator op;

    bool negate;

    std::string string;
    GRegex *regex;

    lb_condition_config(lb_attribute_reference &&a, bool _negate,
                        const char *_string)
        :attribute_reference(std::move(a)), op(Operator::EQUALS),
         negate(_negate), string(_string), regex(nullptr) {}

    lb_condition_config(lb_attribute_reference &&a, bool _negate,
                        GRegex *_regex)
        :attribute_reference(std::move(a)), op(Operator::REGEX),
         negate(_negate), regex(_regex) {}

    lb_condition_config(const lb_condition_config &other)
        :attribute_reference(other.attribute_reference),
         op(other.op), negate(other.negate),
         string(other.string),
         regex(other.op == Operator::REGEX
               ? g_regex_ref(other.regex)
               : nullptr) {}

    lb_condition_config(lb_condition_config &&other)
        :attribute_reference(std::move(other.attribute_reference)),
         op(other.op), negate(other.negate),
         string(std::move(other.string)),
         regex(other.regex) {
        other.regex = nullptr;
    }

    ~lb_condition_config() {
        if (regex != nullptr)
            g_regex_unref(regex);
    }

    gcc_pure
    bool Match(const char *value) const {
        switch (op) {
        case Operator::EQUALS:
            return (string == value) ^ negate;
            break;

        case Operator::REGEX:
            return g_regex_match(regex, value, GRegexMatchFlags(0),
                                 nullptr) ^ negate;
            break;
        }

        gcc_unreachable();
    }
};

struct lb_goto_if_config {
    lb_condition_config condition;

    lb_goto destination;

    lb_goto_if_config(lb_condition_config &&c, lb_goto d)
        :condition(std::move(c)), destination(d) {}
};

/**
 * An object that distributes connections or requests to the "real"
 * cluster.
 */
struct lb_branch_config {
    std::string name;

    lb_goto fallback;

    std::list<lb_goto_if_config> conditions;

    lb_branch_config(const char *_name)
        :name(_name) {}

    bool HasFallback() const {
        return fallback.IsDefined();
    }

    lb_protocol GetProtocol() const {
        return fallback.GetProtocol();
    }
};

inline lb_protocol
lb_goto::GetProtocol() const
{
    assert(IsDefined());

    return cluster != nullptr
        ? cluster->protocol
        : branch->GetProtocol();
}

inline const char *
lb_goto::GetName() const
{
    assert(IsDefined());

    return cluster != nullptr
        ? cluster->name.c_str()
        : branch->name.c_str();
}

struct lb_listener_config {
    std::string name;

    AllocatedSocketAddress bind_address;

    lb_goto destination;

    bool verbose_response = false;

    bool ssl;

    struct ssl_config ssl_config;

    lb_listener_config(const char *_name)
        :name(_name),
         ssl(false) {
    }
};

struct lb_config {
    std::list<lb_control_config> controls;

    std::map<std::string, lb_monitor_config> monitors;

    std::map<std::string, lb_node_config> nodes;

    std::map<std::string, lb_cluster_config> clusters;
    std::map<std::string, lb_branch_config> branches;

    std::list<lb_listener_config> listeners;

    template<typename T>
    gcc_pure
    const lb_monitor_config *FindMonitor(T &&t) const {
        const auto i = monitors.find(std::forward<T>(t));
        return i != monitors.end()
            ? &i->second
            : nullptr;
    }

    template<typename T>
    gcc_pure
    const lb_node_config *FindNode(T &&t) const {
        const auto i = nodes.find(std::forward<T>(t));
        return i != nodes.end()
            ? &i->second
            : nullptr;
    }

    template<typename T>
    gcc_pure
    const lb_cluster_config *FindCluster(T &&t) const {
        const auto i = clusters.find(std::forward<T>(t));
        return i != clusters.end()
            ? &i->second
            : nullptr;
    }

    template<typename T>
    gcc_pure
    const lb_goto FindGoto(T &&t) const {
        lb_goto g;

        g.cluster = FindCluster(t);
        if (g.cluster == nullptr)
            g.branch = FindBranch(std::forward<T>(t));

        return g;
    }

    template<typename T>
    gcc_pure
    const lb_branch_config *FindBranch(T &&t) const {
        const auto i = branches.find(std::forward<T>(t));
        return i != branches.end()
            ? &i->second
            : nullptr;
    }

    template<typename T>
    gcc_pure
    const lb_listener_config *FindListener(T &&t) const {
        for (const auto &i : listeners)
            if (i.name == t)
                return &i;

        return nullptr;
    }
};

G_GNUC_CONST
static inline GQuark
lb_config_quark(void)
{
    return g_quark_from_static_string("lb_config");
}

/**
 * Load and parse the specified configuration file.
 */
struct lb_config *
lb_config_load(struct pool *pool, const char *path, GError **error_r);

#endif
<commit_msg>lb_config: make constructors "explicit"<commit_after>/*
 * Configuration.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_LB_CONFIG_H
#define BENG_LB_CONFIG_H

#include "address_list.hxx"
#include "sticky.h"
#include "ssl_config.hxx"
#include "net/AllocatedSocketAddress.hxx"

#include <http/status.h>

#include <glib.h>

#include <map>
#include <list>
#include <vector>
#include <string>

struct pool;

enum lb_protocol {
    LB_PROTOCOL_HTTP,
    LB_PROTOCOL_TCP,
};

struct lb_control_config {
    AllocatedSocketAddress bind_address;
};

struct lb_monitor_config {
    std::string name;

    /**
     * Time in seconds between two monitor checks.
     */
    unsigned interval;

    /**
     * If the monitor does not produce a result after this timeout
     * [seconds], it is assumed to be negative.
     */
    unsigned timeout;

    enum class Type {
        NONE,
        PING,
        CONNECT,
        TCP_EXPECT,
    } type;

    /**
     * The timeout for establishing a connection.  Only applicable for
     * #Type::TCP_EXPECT.  0 means no special setting present.
     */
    unsigned connect_timeout;

    /**
     * For #Type::TCP_EXPECT: a string that is sent to the peer
     * after the connection has been established.  May be empty.
     */
    std::string send;

    /**
     * For #Type::TCP_EXPECT: a string that is expected to be
     * received from the peer after the #send string has been sent.
     */
    std::string expect;

    /**
     * For #Type::TCP_EXPECT: if that string is received from the
     * peer (instead of #expect), then the node is assumed to be
     * shutting down gracefully, and will only get sticky requests.
     */
    std::string fade_expect;

    explicit lb_monitor_config(const char *_name)
        :name(_name),
         interval(10), timeout(0),
         type(Type::NONE),
         connect_timeout(0) {}
};

struct lb_node_config {
    std::string name;

    AllocatedSocketAddress address;

    /**
     * The Tomcat "jvmRoute" setting of this node.  It is used for
     * #STICKY_JVM_ROUTE.
     */
    std::string jvm_route;

    explicit lb_node_config(const char *_name)
        :name(_name) {}

    lb_node_config(const char *_name, AllocatedSocketAddress &&_address)
        :name(_name), address(std::move(_address)) {}

    lb_node_config(lb_node_config &&src)
        :name(std::move(src.name)), address(std::move(src.address)),
         jvm_route(std::move(src.jvm_route)) {}
};

struct lb_member_config {
    const struct lb_node_config *node;

    unsigned port;

    lb_member_config():node(nullptr), port(0) {}
};

struct lb_fallback_config {
    http_status_t status;

    /**
     * The "Location" response header.
     */
    std::string location;

    std::string message;

    bool IsDefined() const {
        return !location.empty() || !message.empty();
    }
};

struct lb_cluster_config {
    std::string name;

    /**
     * The protocol that is spoken on this cluster.
     */
    enum lb_protocol protocol;

    /**
     * Use the client's source IP for the connection to the backend?
     * This is implemented using IP_TRANSPARENT and requires the
     * "tproxy" Linux kernel module.
     */
    bool transparent_source;

    bool mangle_via;

    struct lb_fallback_config fallback;

    enum sticky_mode sticky_mode;

    std::string session_cookie;

    const struct lb_monitor_config *monitor;

    std::vector<lb_member_config> members;

    /**
     * A list of node addresses.
     */
    AddressList address_list;

    explicit lb_cluster_config(const char *_name)
        :name(_name),
         protocol(LB_PROTOCOL_HTTP),
         transparent_source(false),
         mangle_via(false),
         sticky_mode(STICKY_NONE),
         session_cookie("beng_proxy_session"),
         monitor(nullptr) {}

    /**
     * Returns the member index of the node with the specified
     * jvm_route value, or -1 if not found.
     */
    gcc_pure
    int FindJVMRoute(const char *jvm_route) const;
};

struct lb_attribute_reference {
    enum class Type {
        METHOD,
        URI,
        HEADER,
    } type;

    std::string name;

    template<typename N>
    lb_attribute_reference(Type _type, N &&_name)
        :type(_type), name(std::forward<N>(_name)) {}
};

struct lb_branch_config;

struct lb_goto {
    const lb_cluster_config *cluster;
    const lb_branch_config *branch;

    lb_goto()
        :cluster(nullptr), branch(nullptr) {}

    explicit lb_goto(lb_cluster_config *_cluster)
        :cluster(_cluster), branch(nullptr) {}

    explicit lb_goto(lb_branch_config *_branch)
        :cluster(nullptr), branch(_branch) {}

    bool IsDefined() const {
        return cluster != nullptr || branch != nullptr;
    }

    gcc_pure
    lb_protocol GetProtocol() const;

    gcc_pure
    const char *GetName() const;
};

struct lb_condition_config {
    lb_attribute_reference attribute_reference;

    enum class Operator {
        EQUALS,
        REGEX,
    };

    Operator op;

    bool negate;

    std::string string;
    GRegex *regex;

    lb_condition_config(lb_attribute_reference &&a, bool _negate,
                        const char *_string)
        :attribute_reference(std::move(a)), op(Operator::EQUALS),
         negate(_negate), string(_string), regex(nullptr) {}

    lb_condition_config(lb_attribute_reference &&a, bool _negate,
                        GRegex *_regex)
        :attribute_reference(std::move(a)), op(Operator::REGEX),
         negate(_negate), regex(_regex) {}

    lb_condition_config(const lb_condition_config &other)
        :attribute_reference(other.attribute_reference),
         op(other.op), negate(other.negate),
         string(other.string),
         regex(other.op == Operator::REGEX
               ? g_regex_ref(other.regex)
               : nullptr) {}

    lb_condition_config(lb_condition_config &&other)
        :attribute_reference(std::move(other.attribute_reference)),
         op(other.op), negate(other.negate),
         string(std::move(other.string)),
         regex(other.regex) {
        other.regex = nullptr;
    }

    ~lb_condition_config() {
        if (regex != nullptr)
            g_regex_unref(regex);
    }

    gcc_pure
    bool Match(const char *value) const {
        switch (op) {
        case Operator::EQUALS:
            return (string == value) ^ negate;
            break;

        case Operator::REGEX:
            return g_regex_match(regex, value, GRegexMatchFlags(0),
                                 nullptr) ^ negate;
            break;
        }

        gcc_unreachable();
    }
};

struct lb_goto_if_config {
    lb_condition_config condition;

    lb_goto destination;

    lb_goto_if_config(lb_condition_config &&c, lb_goto d)
        :condition(std::move(c)), destination(d) {}
};

/**
 * An object that distributes connections or requests to the "real"
 * cluster.
 */
struct lb_branch_config {
    std::string name;

    lb_goto fallback;

    std::list<lb_goto_if_config> conditions;

    explicit lb_branch_config(const char *_name)
        :name(_name) {}

    bool HasFallback() const {
        return fallback.IsDefined();
    }

    lb_protocol GetProtocol() const {
        return fallback.GetProtocol();
    }
};

inline lb_protocol
lb_goto::GetProtocol() const
{
    assert(IsDefined());

    return cluster != nullptr
        ? cluster->protocol
        : branch->GetProtocol();
}

inline const char *
lb_goto::GetName() const
{
    assert(IsDefined());

    return cluster != nullptr
        ? cluster->name.c_str()
        : branch->name.c_str();
}

struct lb_listener_config {
    std::string name;

    AllocatedSocketAddress bind_address;

    lb_goto destination;

    bool verbose_response = false;

    bool ssl;

    struct ssl_config ssl_config;

    explicit lb_listener_config(const char *_name)
        :name(_name),
         ssl(false) {
    }
};

struct lb_config {
    std::list<lb_control_config> controls;

    std::map<std::string, lb_monitor_config> monitors;

    std::map<std::string, lb_node_config> nodes;

    std::map<std::string, lb_cluster_config> clusters;
    std::map<std::string, lb_branch_config> branches;

    std::list<lb_listener_config> listeners;

    template<typename T>
    gcc_pure
    const lb_monitor_config *FindMonitor(T &&t) const {
        const auto i = monitors.find(std::forward<T>(t));
        return i != monitors.end()
            ? &i->second
            : nullptr;
    }

    template<typename T>
    gcc_pure
    const lb_node_config *FindNode(T &&t) const {
        const auto i = nodes.find(std::forward<T>(t));
        return i != nodes.end()
            ? &i->second
            : nullptr;
    }

    template<typename T>
    gcc_pure
    const lb_cluster_config *FindCluster(T &&t) const {
        const auto i = clusters.find(std::forward<T>(t));
        return i != clusters.end()
            ? &i->second
            : nullptr;
    }

    template<typename T>
    gcc_pure
    const lb_goto FindGoto(T &&t) const {
        lb_goto g;

        g.cluster = FindCluster(t);
        if (g.cluster == nullptr)
            g.branch = FindBranch(std::forward<T>(t));

        return g;
    }

    template<typename T>
    gcc_pure
    const lb_branch_config *FindBranch(T &&t) const {
        const auto i = branches.find(std::forward<T>(t));
        return i != branches.end()
            ? &i->second
            : nullptr;
    }

    template<typename T>
    gcc_pure
    const lb_listener_config *FindListener(T &&t) const {
        for (const auto &i : listeners)
            if (i.name == t)
                return &i;

        return nullptr;
    }
};

G_GNUC_CONST
static inline GQuark
lb_config_quark(void)
{
    return g_quark_from_static_string("lb_config");
}

/**
 * Load and parse the specified configuration file.
 */
struct lb_config *
lb_config_load(struct pool *pool, const char *path, GError **error_r);

#endif
<|endoftext|>