<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "parser/EDDIGrammar.hpp"
#include "parser/Utils.hpp"

#include "lexer/adapttokens.hpp"
#include "lexer/position.hpp"

using namespace eddic;

parser::EddiGrammar::EddiGrammar(const lexer::Lexer& lexer, const lexer::pos_iterator_type& position_begin) :
        EddiGrammar::base_type(program, "EDDI Grammar"),
        value(lexer, position_begin),
        type(lexer, position_begin),
        position_begin(position_begin){

    else_if_ %=
            lexer.else_
        >>  lexer.if_
        >>  lexer.left_parenth
        >>  value
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    else_ %=
            lexer.else_
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    if_ %=
            lexer.if_
        >>  lexer.left_parenth
        >>  value
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace
        >>  *(else_if_)
        >>  -(else_);

    for_ %=
            lexer.for_
        >   lexer.left_parenth
        >   -declaration
        >   lexer.stop
        >   -value
        >   lexer.stop
        >   -repeatable_instruction
        >   lexer.right_parenth
        >   lexer.left_brace
        >   (*instruction)
        >   lexer.right_brace;

    foreach_ =
            qi::position(position_begin)
        >>  lexer.foreach_
        >>  lexer.left_parenth
        >>  lexer.identifier
        >>  lexer.identifier
        >>  lexer.from_
        >>  lexer.integer
        >>  lexer.to_
        >>  lexer.integer
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    foreachin_ =
            qi::position(position_begin)
        >>  lexer.foreach_
        >>  lexer.left_parenth
        >>  lexer.identifier
        >>  lexer.identifier
        >>  lexer.in_
        >>  lexer.identifier
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    while_ %=
            lexer.while_
        >   lexer.left_parenth
        >   value
        >   lexer.right_parenth
        >   lexer.left_brace
        >   *(instruction)
        >   lexer.right_brace;

    do_while_ %=
            lexer.do_
        >   lexer.left_brace
        >   *(instruction)
        >   lexer.right_brace
        >   lexer.while_
        >   lexer.left_parenth
        >   value
        >   lexer.right_parenth
        >   lexer.stop;

    declaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  -(lexer.assign >> value);

    arrayDeclaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  lexer.left_bracket
        >>  value
        >>  lexer.right_bracket;

    return_ %=
            qi::position(position_begin)
        >>  lexer.return_
        >>  value
        >>  lexer.stop;

    globalDeclaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  -(lexer.assign >> value.constant)
        >>  lexer.stop;

    globalArrayDeclaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  lexer.left_bracket
        >>  value
        >>  lexer.right_bracket
        >>  lexer.stop;

    swap %=
            qi::position(position_begin)
        >>  lexer.identifier
        >>  lexer.swap
        >>  lexer.identifier;

    instruction %=
            (value.function_call > lexer.stop)
        |   (value.assignment > lexer.stop)
        |   (declaration >> lexer.stop)
        |   (value.suffix_operation > lexer.stop)
        |   (value.prefix_operation > lexer.stop)
        |   (arrayDeclaration >> lexer.stop)
        |   if_
        |   for_
        |   while_
        |   do_while_
        |   foreach_
        |   foreachin_
        |   return_
        |   (swap > lexer.stop);

    repeatable_instruction =
            value.assignment
        |   swap
        |   value.suffix_operation
        |   value.prefix_operation
        |   value.function_call;

    arg %=
            type
        >>  lexer.identifier;

    function %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  lexer.left_parenth
        >>  -( arg >> *( lexer.comma > arg))
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    member_declaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  lexer.stop;

    struct_ %=
            qi::position(position_begin)
        >>  lexer.struct_
        >>  lexer.identifier
        >>  lexer.left_brace
        >>  *(member_declaration)
        >>  *(function)
        >>  lexer.right_brace;

    standardImport %=
            lexer.include
        >>  lexer.less
        >>  lexer.identifier
        >>  lexer.greater;

    import %=
            lexer.include
        >>  lexer.litteral;

    program %=
            qi::eps
        >>  qi::position(position_begin)
        >>  *(
                    function
                |   globalDeclaration
                |   globalArrayDeclaration
                |   standardImport
                |   import
                |   struct_
            );

    /* Debugging rules */
    DEBUG_RULE(program);
    DEBUG_RULE(function);
    DEBUG_RULE(instruction);
}
<commit_msg>Add member function call to the instructions<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "parser/EDDIGrammar.hpp"
#include "parser/Utils.hpp"

#include "lexer/adapttokens.hpp"
#include "lexer/position.hpp"

using namespace eddic;

parser::EddiGrammar::EddiGrammar(const lexer::Lexer& lexer, const lexer::pos_iterator_type& position_begin) :
        EddiGrammar::base_type(program, "EDDI Grammar"),
        value(lexer, position_begin),
        type(lexer, position_begin),
        position_begin(position_begin){

    else_if_ %=
            lexer.else_
        >>  lexer.if_
        >>  lexer.left_parenth
        >>  value
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    else_ %=
            lexer.else_
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    if_ %=
            lexer.if_
        >>  lexer.left_parenth
        >>  value
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace
        >>  *(else_if_)
        >>  -(else_);

    for_ %=
            lexer.for_
        >   lexer.left_parenth
        >   -declaration
        >   lexer.stop
        >   -value
        >   lexer.stop
        >   -repeatable_instruction
        >   lexer.right_parenth
        >   lexer.left_brace
        >   (*instruction)
        >   lexer.right_brace;

    foreach_ =
            qi::position(position_begin)
        >>  lexer.foreach_
        >>  lexer.left_parenth
        >>  lexer.identifier
        >>  lexer.identifier
        >>  lexer.from_
        >>  lexer.integer
        >>  lexer.to_
        >>  lexer.integer
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    foreachin_ =
            qi::position(position_begin)
        >>  lexer.foreach_
        >>  lexer.left_parenth
        >>  lexer.identifier
        >>  lexer.identifier
        >>  lexer.in_
        >>  lexer.identifier
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    while_ %=
            lexer.while_
        >   lexer.left_parenth
        >   value
        >   lexer.right_parenth
        >   lexer.left_brace
        >   *(instruction)
        >   lexer.right_brace;

    do_while_ %=
            lexer.do_
        >   lexer.left_brace
        >   *(instruction)
        >   lexer.right_brace
        >   lexer.while_
        >   lexer.left_parenth
        >   value
        >   lexer.right_parenth
        >   lexer.stop;

    declaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  -(lexer.assign >> value);

    arrayDeclaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  lexer.left_bracket
        >>  value
        >>  lexer.right_bracket;

    return_ %=
            qi::position(position_begin)
        >>  lexer.return_
        >>  value
        >>  lexer.stop;

    globalDeclaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  -(lexer.assign >> value.constant)
        >>  lexer.stop;

    globalArrayDeclaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  lexer.left_bracket
        >>  value
        >>  lexer.right_bracket
        >>  lexer.stop;

    swap %=
            qi::position(position_begin)
        >>  lexer.identifier
        >>  lexer.swap
        >>  lexer.identifier;

    instruction %=
            (value.member_function_call > lexer.stop)
        |   (value.function_call > lexer.stop)
        |   (value.assignment > lexer.stop)
        |   (declaration >> lexer.stop)
        |   (value.suffix_operation > lexer.stop)
        |   (value.prefix_operation > lexer.stop)
        |   (arrayDeclaration >> lexer.stop)
        |   if_
        |   for_
        |   while_
        |   do_while_
        |   foreach_
        |   foreachin_
        |   return_
        |   (swap > lexer.stop);

    repeatable_instruction =
            value.assignment
        |   swap
        |   value.suffix_operation
        |   value.prefix_operation
        |   value.function_call;

    arg %=
            type
        >>  lexer.identifier;

    function %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  lexer.left_parenth
        >>  -( arg >> *( lexer.comma > arg))
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    member_declaration %=
            qi::position(position_begin)
        >>  type
        >>  lexer.identifier
        >>  lexer.stop;

    struct_ %=
            qi::position(position_begin)
        >>  lexer.struct_
        >>  lexer.identifier
        >>  lexer.left_brace
        >>  *(member_declaration)
        >>  *(function)
        >>  lexer.right_brace;

    standardImport %=
            lexer.include
        >>  lexer.less
        >>  lexer.identifier
        >>  lexer.greater;

    import %=
            lexer.include
        >>  lexer.litteral;

    program %=
            qi::eps
        >>  qi::position(position_begin)
        >>  *(
                    function
                |   globalDeclaration
                |   globalArrayDeclaration
                |   standardImport
                |   import
                |   struct_
            );

    /* Debugging rules */
    DEBUG_RULE(program);
    DEBUG_RULE(function);
    DEBUG_RULE(instruction);
}
<|endoftext|>


<commit_before>/// \file parser/parse-result.hh

#ifndef PARSER_PARSE_RESULT_HH
# define PARSER_PARSE_RESULT_HH

# include <libport/intrusive-ptr.hh>
# include <list>
# include <string>

# include <ast/error.hh>
# include <ast/nary-fwd.hh>
# include <urbi/export.hh>

namespace parser
{

  /// A structure to record the result of a parsing (AST and errors).
  ///
  /// This structure is used to decouple the parser and all its
  /// internal data from the user's space.  There are two main
  /// advantages.
  ///
  /// Firstly, the user needs little headers to include.
  ///
  /// Secondly, it allows a very functional style: the parsing returns
  /// a single object containing all the aspects of the result, and
  /// keeps no relation to it.  This is much clearer than a previous
  /// interfave where the users had to keep the UParser to ask it
  /// first its ast, then its errors etc.  It was then quite unclear
  /// when such a UParser could be used again for another parsing
  /// session.  Now it's easy: when parsing is done, it's ready for
  /// another one.
  class URBI_SDK_API ParseResult
  {
  public:
    ParseResult();
    ParseResult(ParseResult& rhs);

    /// Errors must have been dumped or cleared.
    /// This is to avoid that parse errors get lost.
    ~ParseResult();

    /// The status as reported by Bison's parser.
    int status;
    /// Whether everything is fine.
    /// The status is 0, the ast is defined, there are no warnings/errors.
    bool good() const;

    /// \name The resulting AST.
    /// \{
    /// The type of AST node returned by the parser.
    typedef ast::rNary ast_type;
    /// The latest AST read by parse().
    ast_type ast_get();
    /// Same as \a ast_get, but assert the result.
    ast_type ast_xget();
    /// Set \a ast_.
    void ast_set(ast_type ast);

  private:
    /// The resulting AST.
    ast_type ast_;
    /// \}

  public:
    /// Declare an error about \a msg.
    void error(const ast::loc& l, const std::string& msg);

    /// Warn about \a msg.
    void warn(const ast::loc& l, const std::string& msg);

    /// Dump all the errors on std::cerr.
    /// For developpers.
    void dump_errors() const;

    /// Push all warning and error messages in \b target.
    /// If errors were pushed, the ast is deleted and set to 0.
    void process_errors(ast::Nary& target);

  private:
    /// List of parse error messages.
    ast::Error errors_;

    /// Whether the errors and warnings were output or given.
    mutable bool reported_;

  public:
    /// Dump for debugging.
    std::ostream& dump(std::ostream& o) const;
  };

  /// Dump \a p on \a o for debugging.
  std::ostream& operator<<(std::ostream& o, const ParseResult& p);
}

# include <parser/parse-result.hxx>

#endif // !PARSER_PARSE_RESULT_HH
<commit_msg>Fix inclusion for WIN32.<commit_after>/// \file parser/parse-result.hh

#ifndef PARSER_PARSE_RESULT_HH
# define PARSER_PARSE_RESULT_HH

# include <libport/intrusive-ptr.hh>
# include <list>
# include <string>

# include <ast/error.hh>
# include <ast/nary.hh>
# include <urbi/export.hh>

namespace parser
{

  /// A structure to record the result of a parsing (AST and errors).
  ///
  /// This structure is used to decouple the parser and all its
  /// internal data from the user's space.  There are two main
  /// advantages.
  ///
  /// Firstly, the user needs little headers to include.
  ///
  /// Secondly, it allows a very functional style: the parsing returns
  /// a single object containing all the aspects of the result, and
  /// keeps no relation to it.  This is much clearer than a previous
  /// interfave where the users had to keep the UParser to ask it
  /// first its ast, then its errors etc.  It was then quite unclear
  /// when such a UParser could be used again for another parsing
  /// session.  Now it's easy: when parsing is done, it's ready for
  /// another one.
  class URBI_SDK_API ParseResult
  {
  public:
    ParseResult();
    ParseResult(ParseResult& rhs);

    /// Errors must have been dumped or cleared.
    /// This is to avoid that parse errors get lost.
    ~ParseResult();

    /// The status as reported by Bison's parser.
    int status;
    /// Whether everything is fine.
    /// The status is 0, the ast is defined, there are no warnings/errors.
    bool good() const;

    /// \name The resulting AST.
    /// \{
    /// The type of AST node returned by the parser.
    typedef ast::rNary ast_type;
    /// The latest AST read by parse().
    ast_type ast_get();
    /// Same as \a ast_get, but assert the result.
    ast_type ast_xget();
    /// Set \a ast_.
    void ast_set(ast_type ast);

  private:
    /// The resulting AST.
    ast_type ast_;
    /// \}

  public:
    /// Declare an error about \a msg.
    void error(const ast::loc& l, const std::string& msg);

    /// Warn about \a msg.
    void warn(const ast::loc& l, const std::string& msg);

    /// Dump all the errors on std::cerr.
    /// For developpers.
    void dump_errors() const;

    /// Push all warning and error messages in \b target.
    /// If errors were pushed, the ast is deleted and set to 0.
    void process_errors(ast::Nary& target);

  private:
    /// List of parse error messages.
    ast::Error errors_;

    /// Whether the errors and warnings were output or given.
    mutable bool reported_;

  public:
    /// Dump for debugging.
    std::ostream& dump(std::ostream& o) const;
  };

  /// Dump \a p on \a o for debugging.
  std::ostream& operator<<(std::ostream& o, const ParseResult& p);
}

# include <parser/parse-result.hxx>

#endif // !PARSER_PARSE_RESULT_HH
<|endoftext|>


<commit_before>/**
 * @file
 *      exercise_03_07.cpp
 * @author
 *      Henrik Samuelsson, henrik.samuelsson(at)gmail.com
 */
#include <iostream>

using std::cout;
using std::endl;
using std::string;

/**
 * @brief
 *      Using a range for loop to change all the characters in a string to x.
 * @details
 *      Almost the same code as in exercise 3.6 but with the loop control
 *      variable explicitly defined as char, which works fine.
 */
int main() {
    string s("Hello World!");

    cout << "Original string = " << s << endl;
    for (char &c : s) {
        c = 'x';
    }
    cout << "String after range for loop = " << s << endl;

    return 0;
}
<commit_msg>Update exercise_03_07.cpp<commit_after>/**
 * @file
 *      exercise_03_07.cpp
 * @author
 *      Henrik Samuelsson, henrik.samuelsson(at)gmail.com
 */
#include <iostream>

using std::cout;
using std::endl;
using std::string;

/**
 * @brief
 *      Using a range for loop to change all the characters in a string to x.
 * @details
 *      Almost the same code as in exercise 3.6 but with the loop control
 *      variable explicitly defined as char reference, which works fine.
 */
int main() {
    string s("Hello World!");

    cout << "Original string = " << s << endl;
    for (char &c : s) {
        c = 'x';
    }
    cout << "String after range for loop = " << s << endl;

    return 0;
}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision: 7837 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html 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.

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

#include "mitkPointSet.h"
#include "mitkPointSetReader.h"
#include "mitkTestingMacros.h"

/**
 *  Test for the class "mitkPointSetReader".
 *
 *  argc and argv are the command line parameters which were passed to
 *  the ADD_TEST command in the CMakeLists.txt file. For the automatic
 *  tests, argv is either empty for the simple tests or contains the filename
 *  of a test data set for the tests (see CMakeLists.txt).
 */
int mitkPointSetReaderTest(int argc , char* argv[])
{
  // always start with this!
  MITK_TEST_BEGIN("PointSetReader")

  // let's create an object of our class
  mitk::PointSetReader::Pointer myPointSetReader = mitk::PointSetReader::New();
  MITK_TEST_CONDITION_REQUIRED(myPointSetReader.IsNotNull(),"Testing instantiation")

  // testing set / get name with invalid data
  std::string testName = "test1";
  myPointSetReader->SetFileName( testName );
  MITK_TEST_CONDITION_REQUIRED( myPointSetReader->GetFileName()== testName, "Testing set / get file name methods!");

  // testing file reading with invalid data
  MITK_TEST_CONDITION_REQUIRED( !myPointSetReader->CanReadFile(testName,"",""), "Testing CanReadFile() method with invalid input file name!");
  myPointSetReader->Update();
  MITK_TEST_CONDITION_REQUIRED( !myPointSetReader->GetSuccess(), "Testing GetSuccess() with invalid input file name!");

  // testing file reading with invalid data
  myPointSetReader->SetFileName(argv[1]);
  MITK_TEST_CONDITION_REQUIRED( myPointSetReader->CanReadFile(argv[1], "", ""), "Testing CanReadFile() method with valid input file name!");
  myPointSetReader->Modified();
  myPointSetReader->Update();
  MITK_TEST_CONDITION_REQUIRED( myPointSetReader->GetSuccess(), "Testing GetSuccess() with valid input file name!");

  // evaluate if the read point set is correct
  mitk::PointSet::Pointer resultPS = myPointSetReader->GetOutput();
  MITK_TEST_CONDITION_REQUIRED( resultPS.IsNotNull(), "Testing output generation!");
  MITK_TEST_CONDITION_REQUIRED( resultPS->GetTimeSteps() == 14, "Testing output time step generation!"); // CAVE: Only valid with the specified test data!
  MITK_TEST_CONDITION_REQUIRED( resultPS->GetPointSet(resultPS->GetTimeSteps()-1)->GetNumberOfPoints() == 0, "Testing output time step generation with empty time step!"); // CAVE: Only valid with the specified test data!

  // always end with this!
  MITK_TEST_END()
}

<commit_msg>Added test invocation check<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision: 7837 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html 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.

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

#include "mitkPointSet.h"
#include "mitkPointSetReader.h"
#include "mitkTestingMacros.h"

/**
 *  Test for the class "mitkPointSetReader".
 *
 *  argc and argv are the command line parameters which were passed to
 *  the ADD_TEST command in the CMakeLists.txt file. For the automatic
 *  tests, argv is either empty for the simple tests or contains the filename
 *  of a test data set for the tests (see CMakeLists.txt).
 */
int mitkPointSetReaderTest(int argc , char** argv)
{
  // always start with this!
  MITK_TEST_BEGIN("PointSetReader")
  MITK_TEST_CONDITION_REQUIRED(argc == 2,"Testing invocation")

  // let's create an object of our class
  mitk::PointSetReader::Pointer myPointSetReader = mitk::PointSetReader::New();
  MITK_TEST_CONDITION_REQUIRED(myPointSetReader.IsNotNull(),"Testing instantiation")

  // testing set / get name with invalid data
  std::string testName = "test1";
  myPointSetReader->SetFileName( testName );
  MITK_TEST_CONDITION_REQUIRED( myPointSetReader->GetFileName()== testName, "Testing set / get file name methods!");

  // testing file reading with invalid data
  MITK_TEST_CONDITION_REQUIRED( !myPointSetReader->CanReadFile(testName,"",""), "Testing CanReadFile() method with invalid input file name!");
  myPointSetReader->Update();
  MITK_TEST_CONDITION_REQUIRED( !myPointSetReader->GetSuccess(), "Testing GetSuccess() with invalid input file name!");

  // testing file reading with invalid data
  myPointSetReader->SetFileName(argv[1]);
  MITK_TEST_CONDITION_REQUIRED( myPointSetReader->CanReadFile(argv[1], "", ""), "Testing CanReadFile() method with valid input file name!");
  myPointSetReader->Modified();
  myPointSetReader->Update();
  MITK_TEST_CONDITION_REQUIRED( myPointSetReader->GetSuccess(), "Testing GetSuccess() with valid input file name!");

  // evaluate if the read point set is correct
  mitk::PointSet::Pointer resultPS = myPointSetReader->GetOutput();
  MITK_TEST_CONDITION_REQUIRED( resultPS.IsNotNull(), "Testing output generation!");
  MITK_TEST_CONDITION_REQUIRED( resultPS->GetTimeSteps() == 14, "Testing output time step generation!"); // CAVE: Only valid with the specified test data!
  MITK_TEST_CONDITION_REQUIRED( resultPS->GetPointSet(resultPS->GetTimeSteps()-1)->GetNumberOfPoints() == 0, "Testing output time step generation with empty time step!"); // CAVE: Only valid with the specified test data!

  // always end with this!
  MITK_TEST_END()
}

<|endoftext|>


<commit_before>/*
    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio

    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 "ch.h"
#include "hal.h"
#include "chprintf.h"

#include "blink.h"
#include "usbconfig.h"
#include "bicycle.h"
#include "kalman.h"
#include "parameters.h"

#include "analog.h"
#include "encoder.h"
#include <boost/math/constants/constants.hpp>

namespace {
    using bicycle_t = model::Bicycle;
    using kalman_t = observer::Kalman<bicycle_t>;

    const float fs = 200; // sample rate [Hz]
    const float dt = 1.0/fs; // sample time [s]
    const float v0 = 5.0; // forward speed [m/s]

    /* Kalman filter variance values */
    const float sigma0 = 1 * constants::as_radians; // yaw angle measurement noise variance
    const float sigma1 = 0.008 * constants::as_radians; // steer angle measurement noise variance

    bicycle_t::input_t u; /* roll torque, steer torque */
    bicycle_t::state_t x; /* yaw angle, roll angle, steer angle, roll rate, steer rate */
    bicycle_t::output_t z; /* yaw angle, steer angle */

    /* sensors */
    Analog analog;
    Encoder encoder(&GPTD5, /* CH1, CH2 connected to PA0, PA1 and NOT enabled by board.h */
            {PAL_NOLINE, /* no index channel */
             152000, /* counts per revolution */
             EncoderConfig::filter_t::CAPTURE_64}); /* 64 * 42 MHz (TIM3 on APB1) = 1.52 us
                                                     * for valid edge */
     const float max_kistler_torque = 25.0f; /* maximum measured steer torque */
} // namespace

/*
 * Application entry point.
 */
int main(void) {

    /*
     * System initializations.
     * - HAL initialization, this also initializes the configured device drivers
     *   and performs the board-specific initializations.
     * - Kernel initialization, the main() function becomes a thread and the
     *   RTOS is active.
     */
    halInit();
    chSysInit();

    /*
     * Initializes a serial-over-USB CDC driver.
     */
    sduObjectInit(&SDU1);
    sduStart(&SDU1, &serusbcfg);

    /*
     * Activates the USB driver and then the USB bus pull-up on D+.
     * Note, a delay is inserted in order to not have to disconnect the cable
     * after a reset.
     */
    board_usb_lld_disconnect_bus();   //usbDisconnectBus(serusbcfg.usbp);
    chThdSleepMilliseconds(1500);
    usbStart(serusbcfg.usbp, &usbcfg);
    board_usb_lld_connect_bus();      //usbConnectBus(serusbcfg.usbp);

    /* create the example thread */
    chBlinkThreadCreateStatic();

    /* initialize bicycle model and states */
    model::Bicycle bicycle(v0, dt);
    x.setZero();

    /* initialize Kalman filter */
    kalman_t kalman(bicycle,
            parameters::defaultvalue::kalman::Q(dt), /* process noise cov */
            (kalman_t::measurement_noise_covariance_t() <<
             sigma0,      0,
                  0, sigma1).finished(),
            bicycle_t::state_t::Zero(), /* set initial state estimate to zero */
            std::pow(x[1]/2, 2) * bicycle_t::state_matrix_t::Identity()); /* error cov */

    /* start analog sensors */
    analog.start();

    /*
     * Normal main() thread activity, in this demo it simulates the bicycle
     * dynamics in real-time (roughly).
     */
    rtcnt_t kalman_update_time = 0;
    while (true) {
        u.setZero();
        u[1] = static_cast<float>(analog.get_adc12()*2.0f*max_kistler_torque/3.3f -
                max_kistler_torque); /* steer torque, read from torque sensor */

        /* set measurement vector */
        z[0] = x[0]; /* yaw angle, just use previous state value */

        /* steer angle, read from encoder (enccnt_t is uint32_t) */
        z[1] = static_cast<float>(encoder.count() /
                boost::math::constants::two_pi<float>());
        if (z[1] >= boost::math::constants::pi<float>()) {
            z[1] -= boost::math::constants::pi<float>();
        }

        /* observer time/measurement update (~512 us) */
        kalman_update_time = chSysGetRealtimeCounterX();
        kalman.time_update(u);
        kalman.measurement_update(z);
        x = kalman.x();
        kalman_update_time = chSysGetRealtimeCounterX() - kalman_update_time;

        chprintf((BaseSequentialStream*)&SDU1,
                "error:\t%0.2f\t%0.2f\t%0.2f\t%0.2f\t%0.2f\r\n",
                x[0], x[1], x[2], x[3], x[4]);
        chprintf((BaseSequentialStream*)&SDU1,
                "kalman update time: %d us\r\n",
                RTC2US(STM32_SYSCLK, kalman_update_time));
        chThdSleepMilliseconds(static_cast<systime_t>(1000*dt));
    }
}
<commit_msg>Fix steer angle limits<commit_after>/*
    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio

    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 "ch.h"
#include "hal.h"
#include "chprintf.h"

#include "blink.h"
#include "usbconfig.h"
#include "bicycle.h"
#include "kalman.h"
#include "parameters.h"

#include "analog.h"
#include "encoder.h"
#include <boost/math/constants/constants.hpp>

namespace {
    using bicycle_t = model::Bicycle;
    using kalman_t = observer::Kalman<bicycle_t>;

    const float fs = 200; // sample rate [Hz]
    const float dt = 1.0/fs; // sample time [s]
    const float v0 = 5.0; // forward speed [m/s]

    /* Kalman filter variance values */
    const float sigma0 = 1 * constants::as_radians; // yaw angle measurement noise variance
    const float sigma1 = 0.008 * constants::as_radians; // steer angle measurement noise variance

    bicycle_t::input_t u; /* roll torque, steer torque */
    bicycle_t::state_t x; /* yaw angle, roll angle, steer angle, roll rate, steer rate */
    bicycle_t::output_t z; /* yaw angle, steer angle */

    /* sensors */
    Analog analog;
    Encoder encoder(&GPTD5, /* CH1, CH2 connected to PA0, PA1 and NOT enabled by board.h */
            {PAL_NOLINE, /* no index channel */
             152000, /* counts per revolution */
             EncoderConfig::filter_t::CAPTURE_64}); /* 64 * 42 MHz (TIM3 on APB1) = 1.52 us
                                                     * for valid edge */
     const float max_kistler_torque = 25.0f; /* maximum measured steer torque */
} // namespace

/*
 * Application entry point.
 */
int main(void) {

    /*
     * System initializations.
     * - HAL initialization, this also initializes the configured device drivers
     *   and performs the board-specific initializations.
     * - Kernel initialization, the main() function becomes a thread and the
     *   RTOS is active.
     */
    halInit();
    chSysInit();

    /*
     * Initializes a serial-over-USB CDC driver.
     */
    sduObjectInit(&SDU1);
    sduStart(&SDU1, &serusbcfg);

    /*
     * Activates the USB driver and then the USB bus pull-up on D+.
     * Note, a delay is inserted in order to not have to disconnect the cable
     * after a reset.
     */
    board_usb_lld_disconnect_bus();   //usbDisconnectBus(serusbcfg.usbp);
    chThdSleepMilliseconds(1500);
    usbStart(serusbcfg.usbp, &usbcfg);
    board_usb_lld_connect_bus();      //usbConnectBus(serusbcfg.usbp);

    /* create the example thread */
    chBlinkThreadCreateStatic();

    /* initialize bicycle model and states */
    model::Bicycle bicycle(v0, dt);
    x.setZero();

    /* initialize Kalman filter */
    kalman_t kalman(bicycle,
            parameters::defaultvalue::kalman::Q(dt), /* process noise cov */
            (kalman_t::measurement_noise_covariance_t() <<
             sigma0,      0,
                  0, sigma1).finished(),
            bicycle_t::state_t::Zero(), /* set initial state estimate to zero */
            std::pow(x[1]/2, 2) * bicycle_t::state_matrix_t::Identity()); /* error cov */

    /* start analog sensors */
    analog.start();

    /*
     * Normal main() thread activity, in this demo it simulates the bicycle
     * dynamics in real-time (roughly).
     */
    rtcnt_t kalman_update_time = 0;
    while (true) {
        u.setZero();
        u[1] = static_cast<float>(analog.get_adc12()*2.0f*max_kistler_torque/3.3f -
                max_kistler_torque); /* steer torque, read from torque sensor */

        /* set measurement vector */
        z[0] = x[0]; /* yaw angle, just use previous state value */

        /* steer angle, read from encoder (enccnt_t is uint32_t) */
        z[1] = static_cast<float>(encoder.count() /
                boost::math::constants::two_pi<float>());
        if (z[1] >= boost::math::constants::pi<float>()) {
            z[1] -= boost::math::constants::two_pi<float>();
        }
        if (z[1] < -boost::math::constants::pi<float>()) {
            z[1] += boost::math::constants::two_pi<float>();
        }

        /* observer time/measurement update (~512 us) */
        kalman_update_time = chSysGetRealtimeCounterX();
        kalman.time_update(u);
        kalman.measurement_update(z);
        x = kalman.x();
        kalman_update_time = chSysGetRealtimeCounterX() - kalman_update_time;

        chprintf((BaseSequentialStream*)&SDU1,
                "error:\t%0.2f\t%0.2f\t%0.2f\t%0.2f\t%0.2f\r\n",
                x[0], x[1], x[2], x[3], x[4]);
        chprintf((BaseSequentialStream*)&SDU1,
                "kalman update time: %d us\r\n",
                RTC2US(STM32_SYSCLK, kalman_update_time));
        chThdSleepMilliseconds(static_cast<systime_t>(1000*dt));
    }
}
<|endoftext|>


<commit_before>/*
	This file is part of the MinSG library extension BlueSurfels.
	Copyright (C) 2014 Claudius Jähn <claudius@uni-paderborn.de>
	Copyright (C) 2016-2017 Sascha Brandt <myeti@mail.uni-paderborn.de>

	This library is subject to the terms of the Mozilla Public License, v. 2.0.
	You should have received a copy of the MPL along with this library; see the
	file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifdef MINSG_EXT_BLUE_SURFELS

#include "SurfelRenderer_FixedSize.h"
#include "SurfelAnalysis.h"

#include "../../Core/FrameContext.h"
#include "../../Core/Statistics.h"
#include "../../Core/Nodes/CameraNode.h"
#include <Rendering/RenderingContext/RenderingContext.h>
#include <Rendering/RenderingContext/RenderingParameters.h>
#include <Rendering/Shader/Shader.h>
#include <Rendering/Shader/Uniform.h>
#include <Rendering/Mesh/Mesh.h>
#include <Rendering/Draw.h>

#include <Geometry/Vec3.h>
#include <Geometry/Vec2.h>

#include <Util/StringIdentifier.h>
#include <Util/GenericAttribute.h>

namespace MinSG{
namespace BlueSurfels {

static const Rendering::Uniform::UniformName uniform_renderSurfels("renderSurfels");
static const Rendering::Uniform::UniformName uniform_surfelRadius("surfelRadius");
static const Util::StringIdentifier SURFEL_ATTRIBUTE("surfels");
static const Util::StringIdentifier SURFEL_MEDIAN_ATTRIBUTE("surfelMedianDist");

#define SURFEL_MEDIAN_COUNT 1000

float SurfelRendererFixedSize::getMedianDist(Node * node, Rendering::Mesh& mesh) {
	auto surfelMedianAttr = node->findAttribute(SURFEL_MEDIAN_ATTRIBUTE);
	float surfelMedianDist = 0;
	if(!surfelMedianAttr) {
		std::cout << "Computing surfel median distance...";
		surfelMedianDist = getMedianOfNthClosestNeighbours(mesh, SURFEL_MEDIAN_COUNT, 2);
		node->setAttribute(SURFEL_MEDIAN_ATTRIBUTE, Util::GenericAttribute::createNumber(surfelMedianDist));
		std::cout << "done!" << std::endl;
	} else {
		surfelMedianDist = surfelMedianAttr->toFloat();
	}
	return surfelMedianDist;
}

static Geometry::Vec2 closestRect(const Geometry::Rect& rect, const Geometry::Vec2& pos) {
	Geometry::Vec2 out(pos);
	if(pos.x() < rect.getMinX())
		out.x(rect.getMinX());
	else if(pos.x() > rect.getMaxX())
		out.x(rect.getMaxX());
	if(pos.y() < rect.getMinY())
		out.y(rect.getMinY());
	else if(pos.y() > rect.getMaxY())
		out.y(rect.getMaxY());
	return out;
}

SurfelRendererFixedSize::SurfelRendererFixedSize() : NodeRendererState(FrameContext::DEFAULT_CHANNEL),
		countFactor(1.0f),sizeFactor(1.0f),surfelSize(1.0f),maxSurfelSize(32.0), maxFrameTime(16.0f),
		debugHideSurfels(false), debugCameraEnabled(false), deferredSurfels(false), adaptive(false), foveated(false) {
		foveatZones.push_back({0.0f, 0.0f});
		foveatZones.push_back({0.5f, 0.5f});
}
SurfelRendererFixedSize::~SurfelRendererFixedSize() {}

NodeRendererResult SurfelRendererFixedSize::displayNode(FrameContext & context, Node * node, const RenderParam & /*rp*/){
	if(!node->isActive())
		return NodeRendererResult::NODE_HANDLED;

	auto& renderingContext = context.getRenderingContext();

	// debugging
	if(debugCameraEnabled && debugCamera.isNull()) {
		debugCamera = static_cast<CameraNode*>(context.getCamera()->clone());
		debugCamera->setWorldTransformation(context.getCamera()->getWorldTransformationSRT());
	}

	Rendering::Mesh* surfelMesh;
	uint32_t maxSurfelCount;
	float surfelMedianDist;
	// get surfels
	std::tie(surfelMesh, maxSurfelCount, surfelMedianDist) = getSurfelsForNode(context, node);

	if( !surfelMesh )
		return NodeRendererResult::PASS_ON;

	// calculate the projected distance between two adjacent pixels in screen space
	float meterPerPixelOriginal = getMeterPerPixel(context, node);
	float meterPerPixel;

	// debugging
	if(debugCameraEnabled) {
		renderingContext.pushMatrix_modelToCamera();
		context.pushAndSetCamera(debugCamera.get());
		meterPerPixel = getMeterPerPixel(context, node);
		context.popCamera();
		renderingContext.popMatrix_modelToCamera();
	} else {
		meterPerPixel = meterPerPixelOriginal;
	}

	float pointSize = this->surfelSize;
	float cFactor = this->countFactor;
	if(foveated) {
		const auto viewport = context.getCamera()->getViewport();
		Geometry::Vec2 vpCenter(viewport.getCenter());
		auto projRect = context.getProjectedRect(node);

		auto it = foveatZones.begin();
		if(it != foveatZones.end())
			vpCenter += {it->first * viewport.getWidth(),it->second * viewport.getHeight()}; // offset
		auto closest = closestRect(projRect, vpCenter);
		float distSqr = closest.distanceSquared(vpCenter);

		if(distSqr > 0) {
			float maxDistSqr = std::min(viewport.getWidth(), viewport.getHeight()) * 0.5f;
			maxDistSqr *= maxDistSqr;
			for(++it; it != foveatZones.end(); ++it) {
				if(distSqr > it->first*it->first*maxDistSqr)
					cFactor = std::min(countFactor, countFactor * it->second);
					//pointSize = surfelSize * it->second;
			}
		}
	}

	float surfelRadius = pointSize * meterPerPixel / 2.0f;
	float minSurfelDistance = surfelMedianDist * std::sqrt(SURFEL_MEDIAN_COUNT / static_cast<float>(maxSurfelCount));

	// Calculate the surfel prefix length based on the estimated median distance between surfels and the coverage of one surfel
	uint32_t surfelPrefixLength = (SURFEL_MEDIAN_COUNT * surfelMedianDist * surfelMedianDist / (surfelRadius * surfelRadius)) * cFactor;

	bool renderOriginal = surfelPrefixLength > maxSurfelCount && minSurfelDistance > surfelRadius;
	if(renderOriginal) {
		uint32_t diff = std::min(maxSurfelCount, surfelPrefixLength - maxSurfelCount);
		surfelPrefixLength = maxSurfelCount - diff;
	}
	surfelPrefixLength = std::min(surfelPrefixLength,maxSurfelCount);

	if(surfelPrefixLength > 0 && (!debugHideSurfels || deferredSurfels)) {
		if(debugCameraEnabled)
			pointSize *= meterPerPixel/meterPerPixelOriginal;
		//pointSize = std::min(pointSize*sizeFactor,this->maxSurfelSize);
		pointSize *= sizeFactor;

		if(deferredSurfels) {
			float camDistSqr = node->getWorldBB().getDistanceSquared(context.getCamera()->getWorldOrigin());
			deferredSurfelQueue.emplace(camDistSqr, node, surfelPrefixLength, pointSize);
			//deferredSurfelQueue.emplace_back(camDistSqr, node, surfelPrefixLength, pointSize);
		} else {
			renderingContext.setGlobalUniform({uniform_renderSurfels, true});
			renderingContext.pushAndSetPointParameters( Rendering::PointParameters(pointSize));
			renderingContext.pushAndSetMatrix_modelToCamera( renderingContext.getMatrix_worldToCamera() );
			renderingContext.multMatrix_modelToCamera(node->getWorldTransformationMatrix());
			context.displayMesh(surfelMesh,	0, surfelPrefixLength );
			renderingContext.popMatrix_modelToCamera();
			renderingContext.popPointParameters();
			renderingContext.setGlobalUniform({uniform_renderSurfels, false});
		}

		return renderOriginal ? NodeRendererResult::PASS_ON : NodeRendererResult::NODE_HANDLED;
	}
	return (debugHideSurfels && !renderOriginal) ? NodeRendererResult::NODE_HANDLED : NodeRendererResult::PASS_ON;
}

SurfelRendererFixedSize::stateResult_t SurfelRendererFixedSize::doEnableState(FrameContext & context, Node * node, const RenderParam & rp) {
	deferredSurfelQueue.clear();

	if(adaptive) {
		float factor = frameTimer.getMilliseconds() / maxFrameTime;
		if(factor > 1.1f || factor < 0.9f) {
			surfelSize = std::min(std::max((3.0f*surfelSize + surfelSize*factor)/4.0f, 1.0f), maxSurfelSize);
		}
		//std::cout << "\r" << avgFrameTime << " " << sizeFactor << "                 " << std::flush;
		frameTimer.reset();
	}

	return NodeRendererState::doEnableState(context, node, rp);
}

void SurfelRendererFixedSize::doDisableState(FrameContext & context, Node * node, const RenderParam & rp) {
	NodeRendererState::doDisableState(context, node, rp);
	if(deferredSurfels && !debugHideSurfels)
		drawSurfels(context);

	if(foveated && debugFoveated) {
		const auto viewport = context.getCamera()->getViewport();
		Geometry::Vec2 vpCenter(viewport.getCenter());

		auto it = foveatZones.begin();
		if(it != foveatZones.end())
			vpCenter += {it->first * viewport.getWidth(),-it->second * viewport.getHeight()}; // offset

		auto& rc = context.getRenderingContext();
		Rendering::enable2DMode(rc, viewport);
		rc.pushAndSetLighting(Rendering::LightingParameters());

		float rad = std::min(viewport.getWidth(), viewport.getHeight()) * 0.5f;
		for(++it; it != foveatZones.end(); ++it) {
			//Geometry::Rect rect(vpCenter.x() - it->first*rad, viewport.getHeight() - vpCenter.y() - it->first*rad, it->first*2*rad, it->first*2*rad);
			//Rendering::drawWireframeRect(context.getRenderingContext(), rect, Util::Color4f(0,0,0.5,1));
			Rendering::drawWireframeCircle(context.getRenderingContext(), vpCenter, it->first*rad, Util::Color4f(0,0,0.5,1));
		}

		rc.popLighting();
		Rendering::disable2DMode(rc);
	}
}

SurfelRendererFixedSize::Surfels_t SurfelRendererFixedSize::getSurfelsForNode(FrameContext & context, Node * node) {
	// get surfel mesh
	auto surfelAttribute = dynamic_cast<Util::ReferenceAttribute<Rendering::Mesh>*>(node->findAttribute( SURFEL_ATTRIBUTE ));
	if(surfelAttribute && surfelAttribute->get()) {
		Rendering::Mesh* surfelMesh = surfelAttribute->get();

		uint32_t maxSurfelCount = surfelMesh->isUsingIndexData() ? surfelMesh->getIndexCount() : surfelMesh->getVertexCount();

		// get median distance between surfels at a fixed prefix length
		float surfelMedianDist = getMedianDist(node, *surfelMesh);

		return {surfelMesh, maxSurfelCount, surfelMedianDist};
	}
	return {nullptr, 0, 0};
}

void SurfelRendererFixedSize::drawSurfels(FrameContext & context, float minSize, float maxSize) const {
	auto& rc = context.getRenderingContext();
	rc.setGlobalUniform({uniform_renderSurfels, true});
	Node* node; uint32_t prefix; float size, distance;
	for(auto& s : deferredSurfelQueue) {
		std::tie(distance, node, prefix, size) = s;
    if(size < minSize || size >= maxSize)
      continue;
		auto surfelAttribute = dynamic_cast<Util::ReferenceAttribute<Rendering::Mesh>*>(node->findAttribute( SURFEL_ATTRIBUTE ));
		auto surfels = surfelAttribute ? surfelAttribute->get() : nullptr;
		rc.pushAndSetPointParameters( Rendering::PointParameters(size));
		rc.pushAndSetMatrix_modelToCamera( rc.getMatrix_worldToCamera() );
		rc.multMatrix_modelToCamera(node->getWorldTransformationMatrix());
		context.displayMesh(surfels,	0, prefix );
		rc.popMatrix_modelToCamera();
		rc.popPointParameters();
	}
	rc.setGlobalUniform({uniform_renderSurfels, false});
}

}
}
#endif // MINSG_EXT_BLUE_SURFELS
<commit_msg>BlueSurfels: interpolate surfel size between fovea zones<commit_after>/*
	This file is part of the MinSG library extension BlueSurfels.
	Copyright (C) 2014 Claudius Jähn <claudius@uni-paderborn.de>
	Copyright (C) 2016-2017 Sascha Brandt <myeti@mail.uni-paderborn.de>

	This library is subject to the terms of the Mozilla Public License, v. 2.0.
	You should have received a copy of the MPL along with this library; see the
	file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifdef MINSG_EXT_BLUE_SURFELS

#include "SurfelRenderer_FixedSize.h"
#include "SurfelAnalysis.h"

#include "../../Core/FrameContext.h"
#include "../../Core/Statistics.h"
#include "../../Core/Nodes/CameraNode.h"
#include <Rendering/RenderingContext/RenderingContext.h>
#include <Rendering/RenderingContext/RenderingParameters.h>
#include <Rendering/Shader/Shader.h>
#include <Rendering/Shader/Uniform.h>
#include <Rendering/Mesh/Mesh.h>
#include <Rendering/Draw.h>

#include <Geometry/Vec3.h>
#include <Geometry/Vec2.h>

#include <Util/StringIdentifier.h>
#include <Util/GenericAttribute.h>

namespace MinSG{
namespace BlueSurfels {

static const Rendering::Uniform::UniformName uniform_renderSurfels("renderSurfels");
static const Rendering::Uniform::UniformName uniform_surfelRadius("surfelRadius");
static const Util::StringIdentifier SURFEL_ATTRIBUTE("surfels");
static const Util::StringIdentifier SURFEL_MEDIAN_ATTRIBUTE("surfelMedianDist");

#define SURFEL_MEDIAN_COUNT 1000

float SurfelRendererFixedSize::getMedianDist(Node * node, Rendering::Mesh& mesh) {
	auto surfelMedianAttr = node->findAttribute(SURFEL_MEDIAN_ATTRIBUTE);
	float surfelMedianDist = 0;
	if(!surfelMedianAttr) {
		std::cout << "Computing surfel median distance...";
		surfelMedianDist = getMedianOfNthClosestNeighbours(mesh, SURFEL_MEDIAN_COUNT, 2);
		node->setAttribute(SURFEL_MEDIAN_ATTRIBUTE, Util::GenericAttribute::createNumber(surfelMedianDist));
		std::cout << "done!" << std::endl;
	} else {
		surfelMedianDist = surfelMedianAttr->toFloat();
	}
	return surfelMedianDist;
}

static Geometry::Vec2 closestRect(const Geometry::Rect& rect, const Geometry::Vec2& pos) {
	Geometry::Vec2 out(pos);
	if(pos.x() < rect.getMinX())
		out.x(rect.getMinX());
	else if(pos.x() > rect.getMaxX())
		out.x(rect.getMaxX());
	if(pos.y() < rect.getMinY())
		out.y(rect.getMinY());
	else if(pos.y() > rect.getMaxY())
		out.y(rect.getMaxY());
	return out;
}

SurfelRendererFixedSize::SurfelRendererFixedSize() : NodeRendererState(FrameContext::DEFAULT_CHANNEL),
		countFactor(1.0f),sizeFactor(1.0f),surfelSize(1.0f),maxSurfelSize(32.0), maxFrameTime(16.0f),
		debugHideSurfels(false), debugCameraEnabled(false), deferredSurfels(false), adaptive(false), foveated(false) {
		foveatZones.push_back({0.0f, 0.0f});
		foveatZones.push_back({0.25f, 1.0f});
		foveatZones.push_back({1.0f, 0.5f});
}
SurfelRendererFixedSize::~SurfelRendererFixedSize() {}

NodeRendererResult SurfelRendererFixedSize::displayNode(FrameContext & context, Node * node, const RenderParam & /*rp*/){
	if(!node->isActive())
		return NodeRendererResult::NODE_HANDLED;

	auto& renderingContext = context.getRenderingContext();

	// debugging
	if(debugCameraEnabled && debugCamera.isNull()) {
		debugCamera = static_cast<CameraNode*>(context.getCamera()->clone());
		debugCamera->setWorldTransformation(context.getCamera()->getWorldTransformationSRT());
	}

	Rendering::Mesh* surfelMesh;
	uint32_t maxSurfelCount;
	float surfelMedianDist;
	// get surfels
	std::tie(surfelMesh, maxSurfelCount, surfelMedianDist) = getSurfelsForNode(context, node);

	if( !surfelMesh )
		return NodeRendererResult::PASS_ON;

	// calculate the projected distance between two adjacent pixels in screen space
	float meterPerPixelOriginal = getMeterPerPixel(context, node);
	float meterPerPixel;

	// debugging
	if(debugCameraEnabled) {
		renderingContext.pushMatrix_modelToCamera();
		context.pushAndSetCamera(debugCamera.get());
		meterPerPixel = getMeterPerPixel(context, node);
		context.popCamera();
		renderingContext.popMatrix_modelToCamera();
	} else {
		meterPerPixel = meterPerPixelOriginal;
	}

	float pointSize = this->surfelSize;
	float cFactor = this->countFactor;
	if(foveated) {
		const auto viewport = context.getCamera()->getViewport();
		Geometry::Vec2 vpCenter(viewport.getCenter());
		auto projRect = context.getProjectedRect(node);

		auto it = foveatZones.begin();
		if(it != foveatZones.end())
			vpCenter += {it->first * viewport.getWidth(),it->second * viewport.getHeight()}; // offset
		float dist = closestRect(projRect, vpCenter).distance(vpCenter);

		if(dist > 0) {
			float maxDist = std::sqrt(viewport.getWidth()*viewport.getWidth() + viewport.getHeight()*viewport.getHeight()) * 0.5f;
			float z1 = 0;
			float z2 = maxDist;
			float c1 = pointSize;
			float c2 = maxSurfelSize;
			for(++it; it != foveatZones.end(); ++it) {
				if(dist < it->first * maxDist) {
					z2 = it->first * maxDist;
					c2 = it->second * pointSize;
					break;
				} else {
					z1 = it->first * maxDist;
					c1 = it->second * pointSize;
				}
			}
			float a = std::min((dist-z1) / (z2-z1), 1.0f);
			//cFactor = (1.0f - a) * c1 + a * c2;
			pointSize = (1.0f - a) * c1 + a * c2;
			//std::cout << "\ra= " << a << ", z1=(" << z1 << "," << c1 << "), z2=(" << z2 << "," << c2 << "), d=" << dist << ", f=" << cFactor << "             " << std::flush;
		}
	}

	float surfelRadius = pointSize * meterPerPixel / 2.0f;
	float minSurfelDistance = surfelMedianDist * std::sqrt(SURFEL_MEDIAN_COUNT / static_cast<float>(maxSurfelCount));

	// Calculate the surfel prefix length based on the estimated median distance between surfels and the coverage of one surfel
	uint32_t surfelPrefixLength = (SURFEL_MEDIAN_COUNT * surfelMedianDist * surfelMedianDist / (surfelRadius * surfelRadius)) * cFactor;

	bool renderOriginal = surfelPrefixLength > maxSurfelCount && minSurfelDistance > surfelRadius;
	if(renderOriginal) {
		uint32_t diff = std::min(maxSurfelCount, surfelPrefixLength - maxSurfelCount);
		surfelPrefixLength = maxSurfelCount - diff;
	}
	surfelPrefixLength = std::min(surfelPrefixLength,maxSurfelCount);

	if(debugHideSurfels && !renderOriginal)
		return NodeRendererResult::NODE_HANDLED;

	if(surfelPrefixLength > 0) {
		if(debugCameraEnabled)
			pointSize *= meterPerPixel/meterPerPixelOriginal;
		//pointSize = std::min(pointSize*sizeFactor,this->maxSurfelSize);
		pointSize *= sizeFactor;

		if(deferredSurfels) {
			float camDistSqr = node->getWorldBB().getDistanceSquared(context.getCamera()->getWorldOrigin());
			deferredSurfelQueue.emplace(camDistSqr, node, surfelPrefixLength, pointSize);
			//deferredSurfelQueue.emplace_back(camDistSqr, node, surfelPrefixLength, pointSize);
		} else {
			renderingContext.setGlobalUniform({uniform_renderSurfels, true});
			renderingContext.pushAndSetPointParameters( Rendering::PointParameters(pointSize));
			renderingContext.pushAndSetMatrix_modelToCamera( renderingContext.getMatrix_worldToCamera() );
			renderingContext.multMatrix_modelToCamera(node->getWorldTransformationMatrix());
			context.displayMesh(surfelMesh,	0, surfelPrefixLength );
			renderingContext.popMatrix_modelToCamera();
			renderingContext.popPointParameters();
			renderingContext.setGlobalUniform({uniform_renderSurfels, false});
		}
	}
	return renderOriginal ? NodeRendererResult::PASS_ON : NodeRendererResult::NODE_HANDLED;
}

SurfelRendererFixedSize::stateResult_t SurfelRendererFixedSize::doEnableState(FrameContext & context, Node * node, const RenderParam & rp) {
	deferredSurfelQueue.clear();

	if(adaptive) {
		float factor = frameTimer.getMilliseconds() / maxFrameTime;
		if(factor > 1.1f || factor < 0.9f) {
			surfelSize = std::min(std::max((3.0f*surfelSize + surfelSize*factor)/4.0f, 1.0f), maxSurfelSize);
		}
		//std::cout << "\r" << avgFrameTime << " " << sizeFactor << "                 " << std::flush;
		frameTimer.reset();
	}

	return NodeRendererState::doEnableState(context, node, rp);
}

void SurfelRendererFixedSize::doDisableState(FrameContext & context, Node * node, const RenderParam & rp) {
	NodeRendererState::doDisableState(context, node, rp);
	if(deferredSurfels && !debugHideSurfels)
		drawSurfels(context);

	if(foveated && debugFoveated) {
		const auto viewport = context.getCamera()->getViewport();
		Geometry::Vec2 vpCenter(viewport.getCenter());

		auto it = foveatZones.begin();
		if(it != foveatZones.end())
			vpCenter += {it->first * viewport.getWidth(),-it->second * viewport.getHeight()}; // offset

		auto& rc = context.getRenderingContext();
		Rendering::enable2DMode(rc, viewport);
		rc.pushAndSetLighting(Rendering::LightingParameters());

		float rad = std::sqrt(viewport.getWidth()*viewport.getWidth() + viewport.getHeight()*viewport.getHeight()) * 0.5f;
		for(++it; it != foveatZones.end(); ++it) {
			//Geometry::Rect rect(vpCenter.x() - it->first*rad, viewport.getHeight() - vpCenter.y() - it->first*rad, it->first*2*rad, it->first*2*rad);
			//Rendering::drawWireframeRect(context.getRenderingContext(), rect, Util::Color4f(0,0,0.5,1));
			Rendering::drawWireframeCircle(context.getRenderingContext(), vpCenter, it->first*rad, Util::Color4f(0,0,0.5,1));
		}

		rc.popLighting();
		Rendering::disable2DMode(rc);
	}
}

SurfelRendererFixedSize::Surfels_t SurfelRendererFixedSize::getSurfelsForNode(FrameContext & context, Node * node) {
	// get surfel mesh
	auto surfelAttribute = dynamic_cast<Util::ReferenceAttribute<Rendering::Mesh>*>(node->findAttribute( SURFEL_ATTRIBUTE ));
	if(surfelAttribute && surfelAttribute->get()) {
		Rendering::Mesh* surfelMesh = surfelAttribute->get();

		uint32_t maxSurfelCount = surfelMesh->isUsingIndexData() ? surfelMesh->getIndexCount() : surfelMesh->getVertexCount();

		// get median distance between surfels at a fixed prefix length
		float surfelMedianDist = getMedianDist(node, *surfelMesh);

		return {surfelMesh, maxSurfelCount, surfelMedianDist};
	}
	return {nullptr, 0, 0};
}

void SurfelRendererFixedSize::drawSurfels(FrameContext & context, float minSize, float maxSize) const {
	auto& rc = context.getRenderingContext();
	rc.setGlobalUniform({uniform_renderSurfels, true});
	Node* node; uint32_t prefix; float size, distance;
	for(auto& s : deferredSurfelQueue) {
		std::tie(distance, node, prefix, size) = s;
    if(size < minSize || size >= maxSize)
      continue;
		auto surfelAttribute = dynamic_cast<Util::ReferenceAttribute<Rendering::Mesh>*>(node->findAttribute( SURFEL_ATTRIBUTE ));
		auto surfels = surfelAttribute ? surfelAttribute->get() : nullptr;
		rc.pushAndSetPointParameters( Rendering::PointParameters(size));
		rc.pushAndSetMatrix_modelToCamera( rc.getMatrix_worldToCamera() );
		rc.multMatrix_modelToCamera(node->getWorldTransformationMatrix());
		context.displayMesh(surfels,	0, prefix );
		rc.popMatrix_modelToCamera();
		rc.popPointParameters();
	}
	rc.setGlobalUniform({uniform_renderSurfels, false});
}

}
}
#endif // MINSG_EXT_BLUE_SURFELS
<|endoftext|>


<commit_before>/**
 * @file main.cpp
 *
 * @author Xu Yuan
 *
 */

#include <glib.h>
#include <glib-object.h>

#include <SimSpark/SimSparkController.h>

#include "Cognition.h"
#include "Motion.h"

using namespace std;

void printUsage(char* name)
{
  cout << "NaoTH Simspark controller" << endl;
  cout << "-------------------------" << endl;
  cout << "http://www.naoteamhumboldt.de" << endl << endl;
  // todo correct it
  cout << "Usage: "<<name<<" [teamname [playernumber [server [port]]]]" << endl << endl;
}

int main(int argc, char** argv)
{
  g_type_init();

  string teamName = "NaoTH";
  gchar* optTeamName = NULL;
  unsigned int num = 0; // zero means get a number from server
  string server = "localhost";
  gchar* optServer = NULL;
  unsigned int port = 3100;
  bool sync = false;

  GOptionEntry entries[] = {
    {"num",'n', 0, G_OPTION_ARG_INT, &num, "player number", "0"},
    {"team", 't', 0, G_OPTION_ARG_STRING, &optTeamName, "team name", "NaoTH"},
    {"server", 's', 0, G_OPTION_ARG_STRING, &optServer, "server host", "localhost"},
    {"port", 'p', 0, G_OPTION_ARG_INT, &port, "server port", "3100"},
    {"sync", 0, 0,  G_OPTION_ARG_NONE, &sync, "sync mode", NULL},
    {NULL} // This is NULL is very important!!!
  };

  GError *error = NULL;
  GOptionContext *context = g_option_context_new("\n-------------------------------\n  http://www.naoth.de");
  g_option_context_add_main_entries (context, entries, "NaoTH Simspark controller");
  if (!g_option_context_parse (context, &argc, &argv, &error))
  {
    g_print ("option parsing failed: %s\n", error->message);
    return EXIT_FAILURE;
  }

  if ( optTeamName != NULL )
  {
    teamName = optTeamName;
    g_free(optTeamName);
  }
  if ( optServer != NULL )
  {
    server = optServer;
    g_free(optServer);
  }
  g_option_context_free(context);

  SimSparkController theController;

  if (!theController.init(teamName, num, server, port, sync))
  {
    cerr << "NaoTH SimSpark initialization failed!" << endl;
    return EXIT_FAILURE;
  }

  Cognition theCognition;
  Motion theMotion;
  theController.registerCallbacks(&theMotion, &theCognition);

  theController.main();

  return 0;
}//end main

<commit_msg>please use -h or --help to see the arguments<commit_after>/**
 * @file main.cpp
 *
 * @author Xu Yuan
 *
 */

#include <glib.h>
#include <glib-object.h>

#include <SimSpark/SimSparkController.h>

#include "Cognition.h"
#include "Motion.h"

using namespace std;

int main(int argc, char** argv)
{
  g_type_init();

  string teamName = "NaoTH";
  gchar* optTeamName = NULL;
  unsigned int num = 0; // zero means get a number from server
  string server = "localhost";
  gchar* optServer = NULL;
  unsigned int port = 3100;
  bool sync = false;

  GOptionEntry entries[] = {
    {"num",'n', 0, G_OPTION_ARG_INT, &num, "player number", "0"},
    {"team", 't', 0, G_OPTION_ARG_STRING, &optTeamName, "team name", "NaoTH"},
    {"server", 's', 0, G_OPTION_ARG_STRING, &optServer, "server host", "localhost"},
    {"port", 'p', 0, G_OPTION_ARG_INT, &port, "server port", "3100"},
    {"sync", 0, 0,  G_OPTION_ARG_NONE, &sync, "sync mode", NULL},
    {NULL} // This is NULL is very important!!!
  };

  GError *error = NULL;
  GOptionContext *context = g_option_context_new("\n-------------------------------\n  http://www.naoth.de");
  g_option_context_add_main_entries (context, entries, "NaoTH Simspark controller");
  if (!g_option_context_parse (context, &argc, &argv, &error))
  {
    g_print ("option parsing failed: %s\n", error->message);
    return EXIT_FAILURE;
  }

  if ( optTeamName != NULL )
  {
    teamName = optTeamName;
    g_free(optTeamName);
  }
  if ( optServer != NULL )
  {
    server = optServer;
    g_free(optServer);
  }
  g_option_context_free(context);

  SimSparkController theController;

  if (!theController.init(teamName, num, server, port, sync))
  {
    cerr << "NaoTH SimSpark initialization failed!" << endl;
    return EXIT_FAILURE;
  }

  Cognition theCognition;
  Motion theMotion;
  theController.registerCallbacks(&theMotion, &theCognition);

  theController.main();

  return 0;
}//end main

<|endoftext|>


<commit_before>#ifndef SOLAIRE_HEX_OSTREAM_HPP
#define SOLAIRE_HEX_OSTREAM_HPP

//Copyright 2015 Adam Smith
//
//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.

// Contact :
// Email             : solairelibrary@mail.com
// GitHub repository : https://github.com/SolaireLibrary/SolaireCPP

/*!
	\file HexOStream.hpp
	\brief
	\author
	Created			: Adam Smith
	Last modified	: Adam Smith
	\date
	Created			: 12th January 2016
	Last Modified	: 12th January 2016
*/

#include "Solaire/Core/OStream.hpp"
#include "Solaire/Maths/Hex.hpp"

namespace Solaire {

	class BinToHexOStream : public OStream {
    private:
        OStream& mStream;
    private:
        // Inherited from OStream

        void SOLAIRE_EXPORT_CALL writeU8(const uint8_t aValue) throw() override {
            char buf[2];
            bin8ToHex(aValue, buf);
            mStream.write(buf, 2);
        }

        void SOLAIRE_EXPORT_CALL writeU16(const uint16_t aValue) throw() override {
            char buf[4];
            bin16ToHex(aValue, buf);
            mStream.write(buf, 4);
        }

        void SOLAIRE_EXPORT_CALL writeU32(const uint32_t aValue) throw() override {
            char buf[8];
            bin16ToHex(aValue, buf);
            mStream.write(buf, 8);
        }

        void SOLAIRE_EXPORT_CALL writeU64(const uint64_t aValue) throw() override {
            char buf[16];
            bin64ToHex(aValue, buf);
            mStream.write(buf, 16);
        }

        void SOLAIRE_EXPORT_CALL writeI8(const int8_t aValue) throw() override {
            char buf[2];
            bin8ToHex(*reinterpret_cast<const uint8_t*>(&aValue), buf);
            mStream.write(buf, 2);
        }

        void SOLAIRE_EXPORT_CALL writeI16(const int16_t aValue) throw() override {
            char buf[4];
            bin16ToHex(*reinterpret_cast<const uint16_t*>(&aValue), buf);
            mStream.write(buf, 4);
        }

        void SOLAIRE_EXPORT_CALL writeI32(const int32_t aValue) throw() override {
            char buf[8];
            bin32ToHex(*reinterpret_cast<const uint32_t*>(&aValue), buf);
            mStream.write(buf, 8);
        }

        void SOLAIRE_EXPORT_CALL writeI64(const int64_t aValue) throw() override {
            char buf[16];
            bin64ToHex(*reinterpret_cast<const uint64_t*>(&aValue), buf);
            mStream.write(buf, 16);
        }

        void SOLAIRE_EXPORT_CALL writeF(const float aValue) throw() override {
            enum{SIZE = sizeof(float) * 2};
            char buf[SIZE];
            binaryToHex(&aValue, sizeof(float), buf, SIZE);
            mStream.write(buf, SIZE);
        }

        void SOLAIRE_EXPORT_CALL writeD(const double aValue) throw() override {
            enum{SIZE = sizeof(double) * 2};
            char buf[SIZE];
            binaryToHex(&aValue, sizeof(double), buf, SIZE);
            mStream.write(buf, SIZE);
        }

        void SOLAIRE_EXPORT_CALL writeC(const char aValue) throw() override {
            char buf[2];
            bin8ToHex(*reinterpret_cast<const uint8_t*>(&aValue), buf);
            mStream.write(buf, 2);
        }

    public:
        BinToHexOStream(OStream& aStream) :
            mStream(aStream)
        {}

        SOLAIRE_EXPORT_CALL ~BinToHexOStream() {

        }

        // Inherited from OStream

        void SOLAIRE_EXPORT_CALL write(const void* const aPtr, const uint32_t aBytes) throw() override {
            const uint32_t size = aBytes * 2;
            char* ptr = new char[size];
            binaryToHex(aPtr, aBytes, ptr, size);
            mStream.write(ptr, size);
            delete[] ptr;
        }

        bool SOLAIRE_EXPORT_CALL isOffsetable() const throw() override {
            return mStream.isOffsetable();
        }

        int32_t SOLAIRE_EXPORT_CALL getOffset() const throw() override {
            return mStream.getOffset();
        }

        bool SOLAIRE_EXPORT_CALL setOffset(const int32_t aOffset) throw() override {
            return mStream.setOffset(aOffset);
        }
    };

}

#endif
<commit_msg>HexToBinOStream<commit_after>#ifndef SOLAIRE_HEX_OSTREAM_HPP
#define SOLAIRE_HEX_OSTREAM_HPP

//Copyright 2015 Adam Smith
//
//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.

// Contact :
// Email             : solairelibrary@mail.com
// GitHub repository : https://github.com/SolaireLibrary/SolaireCPP

/*!
	\file HexOStream.hpp
	\brief
	\author
	Created			: Adam Smith
	Last modified	: Adam Smith
	\date
	Created			: 12th January 2016
	Last Modified	: 12th January 2016
*/

#include "Solaire/Core/OStream.hpp"
#include "Solaire/Maths/Hex.hpp"

namespace Solaire {

	class BinToHexOStream : public OStream {
    private:
        OStream& mStream;
    private:
        // Inherited from OStream

        void SOLAIRE_EXPORT_CALL writeU8(const uint8_t aValue) throw() override {
            char buf[2];
            bin8ToHex(aValue, buf);
            mStream.write(buf, 2);
        }

        void SOLAIRE_EXPORT_CALL writeU16(const uint16_t aValue) throw() override {
            char buf[4];
            bin16ToHex(aValue, buf);
            mStream.write(buf, 4);
        }

        void SOLAIRE_EXPORT_CALL writeU32(const uint32_t aValue) throw() override {
            char buf[8];
            bin16ToHex(aValue, buf);
            mStream.write(buf, 8);
        }

        void SOLAIRE_EXPORT_CALL writeU64(const uint64_t aValue) throw() override {
            char buf[16];
            bin64ToHex(aValue, buf);
            mStream.write(buf, 16);
        }

        void SOLAIRE_EXPORT_CALL writeI8(const int8_t aValue) throw() override {
            char buf[2];
            bin8ToHex(*reinterpret_cast<const uint8_t*>(&aValue), buf);
            mStream.write(buf, 2);
        }

        void SOLAIRE_EXPORT_CALL writeI16(const int16_t aValue) throw() override {
            char buf[4];
            bin16ToHex(*reinterpret_cast<const uint16_t*>(&aValue), buf);
            mStream.write(buf, 4);
        }

        void SOLAIRE_EXPORT_CALL writeI32(const int32_t aValue) throw() override {
            char buf[8];
            bin32ToHex(*reinterpret_cast<const uint32_t*>(&aValue), buf);
            mStream.write(buf, 8);
        }

        void SOLAIRE_EXPORT_CALL writeI64(const int64_t aValue) throw() override {
            char buf[16];
            bin64ToHex(*reinterpret_cast<const uint64_t*>(&aValue), buf);
            mStream.write(buf, 16);
        }

        void SOLAIRE_EXPORT_CALL writeF(const float aValue) throw() override {
            enum{SIZE = sizeof(float) * 2};
            char buf[SIZE];
            binaryToHex(&aValue, sizeof(float), buf, SIZE);
            mStream.write(buf, SIZE);
        }

        void SOLAIRE_EXPORT_CALL writeD(const double aValue) throw() override {
            enum{SIZE = sizeof(double) * 2};
            char buf[SIZE];
            binaryToHex(&aValue, sizeof(double), buf, SIZE);
            mStream.write(buf, SIZE);
        }

        void SOLAIRE_EXPORT_CALL writeC(const char aValue) throw() override {
            char buf[2];
            bin8ToHex(*reinterpret_cast<const uint8_t*>(&aValue), buf);
            mStream.write(buf, 2);
        }

    public:
        BinToHexOStream(OStream& aStream) :
            mStream(aStream)
        {}

        SOLAIRE_EXPORT_CALL ~BinToHexOStream() {

        }

        // Inherited from OStream

        void SOLAIRE_EXPORT_CALL write(const void* const aPtr, const uint32_t aBytes) throw() override {
            const uint32_t size = aBytes * 2;
            char* ptr = new char[size];
            binaryToHex(aPtr, aBytes, ptr, size);
            mStream.write(ptr, size);
            delete[] ptr;
        }

        bool SOLAIRE_EXPORT_CALL isOffsetable() const throw() override {
            return mStream.isOffsetable();
        }

        int32_t SOLAIRE_EXPORT_CALL getOffset() const throw() override {
            return mStream.getOffset();
        }

        bool SOLAIRE_EXPORT_CALL setOffset(const int32_t aOffset) throw() override {
            return mStream.setOffset(aOffset);
        }
    };

    class HexToBinOStream : public OStream {
    private:
        OStream& mStream;
        HexChar mBuffer[2];
        bool mBufferSet;
    private:
        void pushByte(const HexChar aValue) throw() {
            if(mBufferSet) {
                mBuffer[0] = aValue;
                mBufferSet = true;
            }else {
                mBuffer[1] = aValue;
                mBufferSet = false;
                mStream << hexToBin8(mBuffer);
            }
        }

        // Inherited from OStream

        void SOLAIRE_EXPORT_CALL writeU8(const uint8_t aValue) throw() override {
            pushByte(*reinterpret_cast<const HexChar*>(aValue));
        }

        void SOLAIRE_EXPORT_CALL writeU16(const uint16_t aValue) throw() override {
            if(mBufferSet) {
                const HexChar* const ptr = reinterpret_cast<const HexChar*>(&aValue);
                pushByte(ptr[0]);
                pushByte(ptr[1]);
            }else {
                mStream << hexToBin8(reinterpret_cast<const HexChar*>(&aValue));
            }
        }

        void SOLAIRE_EXPORT_CALL writeU32(const uint32_t aValue) throw() override {
            if(mBufferSet) {
                const HexChar* const ptr = reinterpret_cast<const HexChar*>(&aValue);
                pushByte(ptr[0]);
                mStream << hexToBin8(ptr + 1);
                pushByte(ptr[3]);
            }else {
                mStream << hexToBin16(reinterpret_cast<const HexChar*>(&aValue));
            }
        }

        void SOLAIRE_EXPORT_CALL writeU64(const uint64_t aValue) throw() override {
            if(mBufferSet) {
                const HexChar* const ptr = reinterpret_cast<const HexChar*>(&aValue);
                pushByte(ptr[0]);
                mStream << hexToBin16(ptr + 1);
                mStream << hexToBin8(ptr + 5);
                pushByte(ptr[7]);
            }else {
                mStream << hexToBin32(reinterpret_cast<const HexChar*>(&aValue));
            }
        }

        void SOLAIRE_EXPORT_CALL writeI8(const int8_t aValue) throw() override {
            pushByte(*reinterpret_cast<const HexChar*>(aValue));
        }

        void SOLAIRE_EXPORT_CALL writeI16(const int16_t aValue) throw() override {
            if(mBufferSet) {
                const HexChar* const ptr = reinterpret_cast<const HexChar*>(&aValue);
                pushByte(ptr[0]);
                pushByte(ptr[1]);
            }else {
                mStream << hexToBin8(reinterpret_cast<const HexChar*>(&aValue));
            }
        }

        void SOLAIRE_EXPORT_CALL writeI32(const int32_t aValue) throw() override {
            if(mBufferSet) {
                const HexChar* const ptr = reinterpret_cast<const HexChar*>(&aValue);
                pushByte(ptr[0]);
                mStream << hexToBin8(ptr + 1);
                pushByte(ptr[3]);
            }else {
                mStream << hexToBin16(reinterpret_cast<const HexChar*>(&aValue));
            }
        }

        void SOLAIRE_EXPORT_CALL writeI64(const int64_t aValue) throw() override {
            if(mBufferSet) {
                const HexChar* const ptr = reinterpret_cast<const HexChar*>(&aValue);
                pushByte(ptr[0]);
                mStream << hexToBin16(ptr + 1);
                mStream << hexToBin8(ptr + 5);
                pushByte(ptr[7]);
            }else {
                mStream << hexToBin32(reinterpret_cast<const HexChar*>(&aValue));
            }
        }

        void SOLAIRE_EXPORT_CALL writeF(const float aValue) throw() override {
            //! \todo Optimise writeF
            write(&aValue, sizeof(float));
        }

        void SOLAIRE_EXPORT_CALL writeD(const double aValue) throw() override {
            //! \todo Optimise writeD
            write(&aValue, sizeof(double));
        }

        void SOLAIRE_EXPORT_CALL writeC(const char aValue) throw() override {
            pushByte(*reinterpret_cast<const HexChar*>(aValue));
        }

    public:
        HexToBinOStream(OStream& aStream) :
            mStream(aStream),
            mBufferSet(false)
        {}

        SOLAIRE_EXPORT_CALL ~HexToBinOStream() {
            // Handle trailing byte
            if(mBufferSet){
                pushByte('0');
            }
        }

        // Inherited from OStream

        void SOLAIRE_EXPORT_CALL write(const void* const aPtr, const uint32_t aBytes) throw() override {
            const bool trail = aBytes & 1;
            const uint32_t size = trail ? aBytes - 1 : aBytes;
            const HexChar* const src = static_cast<const HexChar*>(aPtr) + (trail ? 1 : 0);
            uint8_t* const dst = new uint8_t[size / 2];
            if(trail) pushByte(*(src - 1));

            hexToBinary(src, size, dst, size / 2);
            mStream.write(dst, size / 2);

            delete[] dst;
        }

        bool SOLAIRE_EXPORT_CALL isOffsetable() const throw() override {
            return mStream.isOffsetable();
        }

        int32_t SOLAIRE_EXPORT_CALL getOffset() const throw() override {
            return mStream.getOffset();
        }

        bool SOLAIRE_EXPORT_CALL setOffset(const int32_t aOffset) throw() override {
            return mStream.setOffset(aOffset);
        }
    };

}

#endif
<|endoftext|>


<commit_before>#include <IRT/visitors/DotLangVisitor.h>

using namespace IRTree;

void CDotLangVisitor::addEdge( const std::string& nodeFromName, const std::string& nodeToName ) {
    treeEdges[nodeFromName].push_back( nodeToName );
}

std::string CDotLangVisitor::GetTraversalInDotLanguage() const {
    std::stringstream sstream;
    sstream << "digraph {" << std::endl;
    sstream << '\t' << "ordering = out;" << std::endl;
    for ( auto it = treeEdges.begin(); it != treeEdges.end(); ++it ) {
        const std::string& fromNode = it->first;
        for ( const std::string& toNode : it->second ) {
            sstream << '\t' << fromNode << " -> " << toNode << ';' << std::endl;
        }
    }
    sstream << '}' << std::endl;

    return sstream.str();
}

void CDotLangVisitor::Clear() {
    treeEdges.clear();
    nodeTypeLastUsedIndex.clear();
    visitedNodeStack.clear();
}

/*__________ Expressions __________*/

void CDotLangVisitor::Visit( const CConstExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_CONST );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Value" ) + ": ";
    valueNodeName += std::to_string( expression->Value() ) + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CNameExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_NAME );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Label" ) + ": ";
    valueNodeName += expression->Label().ToString() + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CTempExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_TEMP );
    onNodeEnter( nodeName );

    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Temp" ) + ": ";
    valueNodeName += expression->Temporary().ToString() + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CBinaryExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_BINARY );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    expression->LeftOperand()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    addEdge( nodeName, generateNodeName( operatorName( expression->Operation() ) ) );

    expression->RightOperand()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CMemExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_MEM );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    expression->Address()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CCallExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_CALL );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    expression->Function()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    expression->Arguments()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CEseqExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_ESEQ );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    expression->Statement()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    expression->Expression()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

/*__________ Statements __________*/

void CDotLangVisitor::Visit( const CExpStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_EXP );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    statement->Expression()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CJumpConditionalStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_CJUMP );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    statement->LeftOperand()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->RightOperand()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->TrueLabel()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->FalseLabel()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CJumpStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_JUMP );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Label" ) + ": ";
    valueNodeName += statement->Target().ToString() + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CLabelStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_LABEL );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Label" ) + ": ";
    valueNodeName += statement->Label().ToString() + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CMoveStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_MOVE );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    statement->Destination()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->Source()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CSeqStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_SEQ );
    onNodeEnter( nodeName );

    onNodeExit( nodeName );
}

/*__________  Lists __________*/

void CDotLangVisitor::Visit( const CExpressionList* list ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_LIST );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    const std::vector<std::unique_ptr<const CExpression>>& expressions = list->Expressions();
    for ( auto it = expressions.begin(); it != expressions.end(); ++it ) {
        ( *it )->Accept( this );

        addEdge( nodeName, visitedNodeStack.back() );
        visitedNodeStack.pop_back();
    }

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CStatementList* list ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_LIST );
    onNodeEnter( nodeName );

    visitedNodeStack.push_back( nodeName );

    const std::vector< std::unique_ptr<const CStatement> >& statements = list->Statements();
    for ( auto it = statements.begin(); it != statements.end(); ++it ) {
        ( *it )->Accept( this );

        addEdge( nodeName, visitedNodeStack.back() );
        visitedNodeStack.pop_back();
    }

    onNodeExit( nodeName );
}
<commit_msg>IRTree::DotLangVisitor created + forgotten CSeqStatement added<commit_after>#include <IRT/visitors/DotLangVisitor.h>

using namespace IRTree;

void CDotLangVisitor::addEdge( const std::string& nodeFromName, const std::string& nodeToName ) {
    treeEdges[nodeFromName].push_back( nodeToName );
}

std::string CDotLangVisitor::GetTraversalInDotLanguage() const {
    std::stringstream sstream;
    sstream << "digraph {" << std::endl;
    sstream << '\t' << "ordering = out;" << std::endl;
    for ( auto it = treeEdges.begin(); it != treeEdges.end(); ++it ) {
        const std::string& fromNode = it->first;
        for ( const std::string& toNode : it->second ) {
            sstream << '\t' << fromNode << " -> " << toNode << ';' << std::endl;
        }
    }
    sstream << '}' << std::endl;

    return sstream.str();
}

void CDotLangVisitor::Clear() {
    treeEdges.clear();
    nodeTypeLastUsedIndex.clear();
    visitedNodeStack.clear();
}

/*__________ Expressions __________*/

void CDotLangVisitor::Visit( const CConstExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_CONST );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Value" ) + ": ";
    valueNodeName += std::to_string( expression->Value() ) + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CNameExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_NAME );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Label" ) + ": ";
    valueNodeName += expression->Label().ToString() + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CTempExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_TEMP );
    onNodeEnter( nodeName );

    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Temp" ) + ": ";
    valueNodeName += expression->Temporary().ToString() + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CBinaryExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_BINARY );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    expression->LeftOperand()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    addEdge( nodeName, generateNodeName( operatorName( expression->Operation() ) ) );

    expression->RightOperand()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CMemExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_MEM );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    expression->Address()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CCallExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_CALL );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    expression->Function()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    expression->Arguments()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CEseqExpression* expression ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_ESEQ );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    expression->Statement()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    expression->Expression()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

/*__________ Statements __________*/

void CDotLangVisitor::Visit( const CExpStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_EXP );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    statement->Expression()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CJumpConditionalStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_CJUMP );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    statement->LeftOperand()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->RightOperand()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->TrueLabel()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->FalseLabel()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CJumpStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_JUMP );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Label" ) + ": ";
    valueNodeName += statement->Target().ToString() + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CLabelStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_LABEL );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    std::string valueNodeName = "\"" + generateNodeName( "Label" ) + ": ";
    valueNodeName += statement->Label().ToString() + "\"";
    addEdge( nodeName, valueNodeName );

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CMoveStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_MOVE );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    statement->Destination()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->Source()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CSeqStatement* statement ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_SEQ );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    statement->LeftStatement()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    statement->RightStatement()->Accept( this );
    addEdge( nodeName, visitedNodeStack.back() );
    visitedNodeStack.pop_back();

    onNodeExit( nodeName );
}

/*__________  Lists __________*/

void CDotLangVisitor::Visit( const CExpressionList* list ) {
    std::string nodeName = generateNodeName( CNodeNames::EXP_LIST );
    onNodeEnter( nodeName );
    visitedNodeStack.push_back( nodeName );

    const std::vector<std::unique_ptr<const CExpression>>& expressions = list->Expressions();
    for ( auto it = expressions.begin(); it != expressions.end(); ++it ) {
        ( *it )->Accept( this );

        addEdge( nodeName, visitedNodeStack.back() );
        visitedNodeStack.pop_back();
    }

    onNodeExit( nodeName );
}

void CDotLangVisitor::Visit( const CStatementList* list ) {
    std::string nodeName = generateNodeName( CNodeNames::STAT_LIST );
    onNodeEnter( nodeName );

    visitedNodeStack.push_back( nodeName );

    const std::vector< std::unique_ptr<const CStatement> >& statements = list->Statements();
    for ( auto it = statements.begin(); it != statements.end(); ++it ) {
        ( *it )->Accept( this );

        addEdge( nodeName, visitedNodeStack.back() );
        visitedNodeStack.pop_back();
    }

    onNodeExit( nodeName );
}
<|endoftext|>


<commit_before>#include "FSRespSource.h"

#include <type_traits>
#include <stdexcept>

#include <boost/locale.hpp>

#include "CommonErrorRespSource.h"
#include "detail/MimeDB.h"

using namespace HTTP;
using namespace HTTP::RespSource;

FS::Response::Response(const boost::filesystem::path &FileName, const char *MimeType, time_t IfModifiedSince) : MyMimeType(MimeType)
{
	time_t LastModTime=boost::filesystem::last_write_time(FileName);
	Header::FormatDateTime(LastModTime,LastModifiedStr);

	if ((!IfModifiedSince) || (LastModTime>IfModifiedSince))
	{
		FileSize=boost::filesystem::file_size(FileName);
		FilePos=0;

		InS.open(FileName.string(),std::ios_base::binary);
		if (!InS.is_open())
			throw std::exception("Cannot open target file");
	}
	else
	{
		FileSize=NotModifiedSize;
		FilePos=0;
	}
}

bool FS::Response::GetExtraHeader(unsigned int Index,
	const char **OutHeader, const char **OutHeaderEnd,
	const char **OutHeaderVal, const char **OutHeaderValEnd)
{
	if (Index==0)
	{
		const std::string &HName=Header::GetHeaderName(HN_LAST_MODIFIED);
		*OutHeader=HName.data();
		*OutHeaderEnd=HName.data() + HName.size();
		*OutHeaderVal=LastModifiedStr;
		*OutHeaderValEnd=LastModifiedStr+sizeof(LastModifiedStr);

		return true;
	}
	else
		return false;
}

bool FS::Response::Read(unsigned char *TargetBuff, unsigned int MaxLength, unsigned int &OutLength,
		boost::asio::yield_context &Ctx)
{
	if (FileSize!=NotModifiedSize)
	{
		unsigned long long RemLength=FileSize-FilePos;
		if (MaxLength>RemLength)
			MaxLength=(unsigned int)RemLength;

		InS.read((char *)TargetBuff,MaxLength);

		OutLength=MaxLength;
		FilePos+=MaxLength;

		return (FilePos==FileSize) || (InS.fail());
	}
	else
	{
		OutLength=0;
		return true;
	}
}

FS::FS(const boost::filesystem::path &NewRoot) : Root(NewRoot)
{
}

IResponse *FS::Create(METHOD Method, const std::string &Resource, const QueryParams &Query, const std::vector<Header> &HeaderA,
		const unsigned char *ContentBuff, const unsigned char *ContentBuffEnd,
		boost::asio::io_service &ParentIOS, void *ParentConn)
{
	boost::filesystem::path Target;
	try
	{
		if (std::is_same<boost::filesystem::path::value_type,wchar_t>())
			Target=boost::filesystem::canonical(Root / boost::locale::conv::utf_to_utf<wchar_t,char>(Resource));
		else
			Target=boost::filesystem::canonical(Root / Resource);
	}
	catch (...)
	{ return new CommonError::Response(Resource,HeaderA,NULL,RC_NOTFOUND); }

  if ( (std::distance(Root.begin(), Root.end())<=std::distance(Target.begin(), Target.end())) &&
	  (std::equal(Root.begin(), Root.end(), Target.begin())) &&
	  (boost::filesystem::exists(Target)) )
  {
	  time_t IfModSinceTime=0;
	  try
	  {
		  for (const Header &CurrH : HeaderA)
		  {
			  if (CurrH.IntName==HN_IF_MOD_SINCE)
			  {
				  IfModSinceTime=CurrH.GetDateTime();
				  break;
			  }
		  }
	  }
	  catch (...) { }

	  if (!boost::filesystem::is_directory(Target))
		  return new Response(Target,GetMimeType(Target),IfModSinceTime);
	  else
		  return new CommonError::Response(Resource,HeaderA,NULL,RC_FORBIDDEN);
  }
  else
	  return new CommonError::Response(Resource,HeaderA,NULL,RC_NOTFOUND);
}

const char *FS::GetMimeType(const boost::filesystem::path &FileName)
{
	return detail::MimeDB::GetMimeType(FileName.extension().string());
}
<commit_msg>RespSource::FS::Response ctor: exception and stream open fix<commit_after>#include "FSRespSource.h"

#include <type_traits>
#include <stdexcept>

#include <boost/locale.hpp>

#include "CommonErrorRespSource.h"
#include "detail/MimeDB.h"

using namespace HTTP;
using namespace HTTP::RespSource;

FS::Response::Response(const boost::filesystem::path &FileName, const char *MimeType, time_t IfModifiedSince) : MyMimeType(MimeType)
{
	time_t LastModTime=boost::filesystem::last_write_time(FileName);
	Header::FormatDateTime(LastModTime,LastModifiedStr);

	if ((!IfModifiedSince) || (LastModTime>IfModifiedSince))
	{
		FileSize=boost::filesystem::file_size(FileName);
		FilePos=0;

		InS.open(FileName.string().data(),std::ios_base::binary);
		if (!InS.is_open())
			throw std::runtime_error("Cannot open target file");
	}
	else
	{
		FileSize=NotModifiedSize;
		FilePos=0;
	}
}

bool FS::Response::GetExtraHeader(unsigned int Index,
	const char **OutHeader, const char **OutHeaderEnd,
	const char **OutHeaderVal, const char **OutHeaderValEnd)
{
	if (Index==0)
	{
		const std::string &HName=Header::GetHeaderName(HN_LAST_MODIFIED);
		*OutHeader=HName.data();
		*OutHeaderEnd=HName.data() + HName.size();
		*OutHeaderVal=LastModifiedStr;
		*OutHeaderValEnd=LastModifiedStr+sizeof(LastModifiedStr);

		return true;
	}
	else
		return false;
}

bool FS::Response::Read(unsigned char *TargetBuff, unsigned int MaxLength, unsigned int &OutLength,
		boost::asio::yield_context &Ctx)
{
	if (FileSize!=NotModifiedSize)
	{
		unsigned long long RemLength=FileSize-FilePos;
		if (MaxLength>RemLength)
			MaxLength=(unsigned int)RemLength;

		InS.read((char *)TargetBuff,MaxLength);

		OutLength=MaxLength;
		FilePos+=MaxLength;

		return (FilePos==FileSize) || (InS.fail());
	}
	else
	{
		OutLength=0;
		return true;
	}
}

FS::FS(const boost::filesystem::path &NewRoot) : Root(NewRoot)
{
}

IResponse *FS::Create(METHOD Method, const std::string &Resource, const QueryParams &Query, const std::vector<Header> &HeaderA,
		const unsigned char *ContentBuff, const unsigned char *ContentBuffEnd,
		boost::asio::io_service &ParentIOS, void *ParentConn)
{
	boost::filesystem::path Target;
	try
	{
		if (std::is_same<boost::filesystem::path::value_type,wchar_t>())
			Target=boost::filesystem::canonical(Root / boost::locale::conv::utf_to_utf<wchar_t,char>(Resource));
		else
			Target=boost::filesystem::canonical(Root / Resource);
	}
	catch (...)
	{ return new CommonError::Response(Resource,HeaderA,NULL,RC_NOTFOUND); }

  if ( (std::distance(Root.begin(), Root.end())<=std::distance(Target.begin(), Target.end())) &&
	  (std::equal(Root.begin(), Root.end(), Target.begin())) &&
	  (boost::filesystem::exists(Target)) )
  {
	  time_t IfModSinceTime=0;
	  try
	  {
		  for (const Header &CurrH : HeaderA)
		  {
			  if (CurrH.IntName==HN_IF_MOD_SINCE)
			  {
				  IfModSinceTime=CurrH.GetDateTime();
				  break;
			  }
		  }
	  }
	  catch (...) { }

	  if (!boost::filesystem::is_directory(Target))
		  return new Response(Target,GetMimeType(Target),IfModSinceTime);
	  else
		  return new CommonError::Response(Resource,HeaderA,NULL,RC_FORBIDDEN);
  }
  else
	  return new CommonError::Response(Resource,HeaderA,NULL,RC_NOTFOUND);
}

const char *FS::GetMimeType(const boost::filesystem::path &FileName)
{
	return detail::MimeDB::GetMimeType(FileName.extension().string());
}
<|endoftext|>