text:
#include <boost/algorithm/string/predicate.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/filesystem.hpp>
#include "Conversion.hpp"
#include "Environment.hpp"
#include "Serialize.hpp"
#include "Settings.hpp"

using namespace std;

const string Settings::SETTINGS_FILENAME = "swyrm.ini";
const string Settings::KEYBINDING_PREFIX = "key_";

// Find the ini file (first check the user's home directory, then the
// game directory).  Parse it into the boost::ptree so that it can be
// later queried for languages, keybindings, etc.
Settings::Settings(const bool read_from_disk, const bool read_user_copy)
{
  if (read_from_disk)
  {
    string ini_file_loc = SETTINGS_FILENAME;

    if (read_user_copy)
    {
      string dir = Environment::get_userdata_directory(nullptr);
      ini_file_loc = dir + SETTINGS_FILENAME;
    }

    if (boost::filesystem::exists(ini_file_loc))
    {
      boost::property_tree::ini_parser::read_ini(ini_file_loc, settings_tree);
    }
  }
}

// Merge the user settings. This merges all settings except those that start
// with a '_'
bool Settings::merge_user_settings(const Settings& user_settings)
{
  int count = 0;

  for (auto& u_it : user_settings.get_settings_tree())
  {
    string name = u_it.first;

    if (!name.empty() && name[0] != '_')
    {
      set_setting(name, u_it.second.data());
      count++;
    }
  }

  return (count > 0);
}

// Look up a setting
string Settings::get_setting(const string& key) const
{
  string setting;

  setting = settings_tree.get<string>(key, "");

  return setting;
}

void Settings::set_setting(const string& name, const string& val)
{
  settings_tree.put(name, val);
}

void Settings::set_settings(const map<string, string>& addl_settings)
{
  for (const auto& s_pair : addl_settings)
  {
    settings_tree.put(s_pair.first, s_pair.second);
  }
}

// Get all the keybindings.  Keybindings are the settings that start with
// "key_".
map<string, string> Settings::get_keybindings() const
{
  map<string, string> keybindings;

  for (boost::property_tree::ptree::const_iterator iter = settings_tree.begin(); iter != settings_tree.end(); iter++)
  {
    string key = iter->first;

    if (boost::starts_with(key, KEYBINDING_PREFIX))
    {
      keybindings[iter->first] = iter->second.data();
    }
  }

  return keybindings;
}

bool Settings::get_setting_as_bool(const string& key, const bool default_val) const
{
  string setting = get_setting(key);
  bool settingb = default_val;

  if (!setting.empty())
  {
    settingb = String::to_bool(get_setting(key));
  }

  return settingb;
}

map<string, string> Settings::get_settings_starts_with(const string& key_prefix) const
{
  map<string, string> props;
  for (auto it : settings_tree)
  {
    if (it.first.rfind(key_prefix) == 0)
    {
      props[it.first] = it.second.data();
    }
  }

  return props;
}

boost::property_tree::ptree Settings::get_settings_tree() const
{
  return settings_tree;
}

bool Settings::serialize(ostream& stream) const
{
  stringstream ss;
  boost::property_tree::write_ini(ss, settings_tree);
  string prop_str = ss.str();

  Serialize::write_string(stream, prop_str);

  return true;
}

bool Settings::deserialize(istream& stream)
{
  string prop_str;
  Serialize::read_string(stream, prop_str);
  stringstream ss;
  ss << prop_str;

  boost::property_tree::read_ini(ss, settings_tree);

  return true;
}

ClassIdentifier Settings::internal_class_identifier() const
{
  return ClassIdentifier::CLASS_ID_SETTINGS;
}

max_stars_repo_name: prolog/shadow-of-the-wyrm

max_issues_repo_name: prolog/shadow-of-the-wyrm

max_forks_repo_name: prolog/shadow-of-the-wyrm


text:
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <iostream>
#include <string>
#include <vector>

#include "common/check.h"
#include "common/statics.h"

using namespace std;
namespace po = boost::program_options;

void OutputData(unsigned int bytes, unsigned int lines,
                unsigned int chunks_per_line,
                bool flush_lines, bool flush_chunks,
                const vector<char>& byte_source) {
  if (bytes == 0) {
  cout << "DATA\nENDDATA\n";
    return;
  }
  CHECK(byte_source.size() >= bytes);

  unsigned int bytes_per_line = bytes / lines;
  unsigned int bytes_per_chunk = bytes_per_line / chunks_per_line;

  cout << "DATA\n";

  int byte_source_ptr = 0;
  for (unsigned int i = 0; i < lines; ++i) {
    for (unsigned int j = 0; j < chunks_per_line; ++j) {
      cout.write(&byte_source[byte_source_ptr], bytes_per_chunk);
      byte_source_ptr += bytes_per_chunk;
      if (flush_chunks) {
        cout.flush();
      }
    }
    cout << "\n";
    if (flush_lines) {
      cout.flush();
    }
  }

  cout << "ENDDATA\n";
}

int main(int argc, char** argv) {
  Initialize();
  int response_bytes, response_lines, chunks_per_line;
  bool flush_each_line, flush_each_chunk;
  po::options_description desc("Options:");
  desc.add_options()
      ("help,h", "Print help message")
      ("response_bytes,b", po::value<int>(&response_bytes)->default_value(0),
       "In response to 'GO' this will send this many bytes of data before "
       "sending READY")
      ("response_lines,l", po::value<int>(&response_lines)->default_value(1),
       "The --response_bytes bytes of data will be split over this many "
       "lines of output")
      ("chunks_per_line,c", po::value<int>(&chunks_per_line)->default_value(1),
       "Each line of output will be output is this many different pieces")
      ("flush_each_line",
       po::bool_switch(&flush_each_line)->default_value(false),
       "If true cout.flush() is called after each line is written")
      ("flush_each_chunk",
       po::bool_switch(&flush_each_chunk)->default_value(false),
       "If true cout.flush() is called after each chunk is written.");

  po::variables_map vm;
  po::store(po::parse_command_line(argc, argv, desc), vm);
  po::notify(vm);
  if (vm.count("help")) {
    cout << desc << endl;
    exit(0);
  }
  if (response_bytes != 0) {
    CHECK(response_bytes > 0);
    CHECK(response_lines >= 1);
    CHECK(response_bytes >= response_lines);
    CHECK(response_bytes % response_lines == 0);
    CHECK(chunks_per_line <= (response_bytes/response_lines));
    CHECK((response_bytes/response_lines) % chunks_per_line == 0);
  }

  // Initialize a source of byte data so we don't have to pay the cost to
  // initialize it over and over.
  vector<char> byte_source;
  // We don't anticipate generate more than 1 meg/"GO" so no need to generate
  // more data than that.
  const int MAX_BYTES = 1 << 20;
  CHECK(response_bytes < MAX_BYTES);
  for (int i = 0; i < MAX_BYTES; ++i) {
   byte_source.push_back(i % 256);
  }

  // Disable stdio synching for performance
  ios_base::sync_with_stdio(false);

  cout << "READY" << endl;
  while (cin.good()) {
    string line;
    getline(cin, line);
    if (line == "GO") {
      OutputData(response_bytes, response_lines, chunks_per_line,
                 flush_each_line, flush_each_chunk,
                 byte_source);
      cout << "READY" << endl;
    } else if (line == "SHUTDOWN") {
      exit(0);
    }
  }

  return 0;
}

ext: cc

max_stars_repo_name: nathanawmk/SPARTA

max_issues_repo_name: nathanawmk/SPARTA

max_forks_repo_name: nathanawmk/SPARTA


text:
#include "Window2D.h"
#include "Camera2D.h"
#include <iostream>
#include <Eigen/Geometry>
#include "GL/glut.h"
std::vector<Window2D*> Window2D::mWindows;
std::vector<int> Window2D::mWinIDs;
Window2D::
Window2D()
	:mCamera(new Camera2D()),mIsDrag(false),mMouseType(0),mPrevX(0),mPrevY(0),mDisplayTimeout(1.0/30.0)
{
}
Window2D::
~Window2D()
{
}
void
Window2D::
InitWindow(int _w,int _h,const char* _name)
{
	mWindows.push_back(this);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE | GLUT_ACCUM);
	glutInitWindowPosition(150, 100);
	glutInitWindowSize(_w, _h);
	mWinIDs.push_back(glutCreateWindow(_name));
	  glutDisplayFunc(DisplayEvent);
  glutReshapeFunc(ReshapeEvent);
  glutKeyboardFunc(KeyboardEvent);
  glutMouseFunc(MouseEvent);
  glutMotionFunc(MotionEvent);
  glutTimerFunc(mDisplayTimeout, TimerEvent, 0);
}
inline Window2D* Window2D::current() {
  int id = glutGetWindow();
  for (unsigned int i = 0; i < mWinIDs.size(); i++) {
    if (mWinIDs.at(i) == id) {
      return mWindows.at(i);
    }
  }
  std::cout << "An unknown error occurred!" << std::endl;
  exit(0);
}
void
Window2D::
DisplayEvent()
{
	current()->Display();
}
void
Window2D::
KeyboardEvent(unsigned char key,int x,int y)
{
	current()->Keyboard(key,x,y);
}
void
Window2D::
MouseEvent(int button, int state, int x, int y)
{
	current()->Mouse(button,state,x,y);
}
void
Window2D::
MotionEvent(int x, int y)
{
	current()->Motion(x,y);
}
void
Window2D::
ReshapeEvent(int w, int h)
{
	current()->Reshape(w,h);
}
void
Window2D::
TimerEvent(int value)
{
	current()->Timer(value);
}

ext: cpp


text:
#include <iostream>

#include <boost/algorithm/string.hpp>

#include <redox/redox.hpp>

#include <json/json.hpp>

#include <nghttp2/asio_http2_server.h>

using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
using json = nlohmann::json;

generator_cb loading_templete(std::string path, const response &res) {
    auto fd = open(path.c_str(), O_RDONLY);

    if (fd == -1) {
        return 0;
    }

    return file_generator_from_fd(fd);
}

std::string getParamters(std::string uri, int count) {
    std::vector<std::string> strs;
    boost::split(strs, uri, boost::is_any_of("/"));

    return strs[count];
}

int main(int argc, char *argv[]) {
    boost::system::error_code ec;
    boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);

    tls.use_private_key_file("../static/cert/privkey1.pem", boost::asio::ssl::context::pem);
    tls.use_certificate_chain_file("../static/cert/cert1.pem");

    configure_tls_context_easy(ec, tls);

    http2 server;

    redox::Redox rdx;
    rdx.connect("172.17.0.3", 6379);

    //config
    std::string port = "443";

    std::cout << "uniquehttp2 is loading..." << std::endl;

    std::string style_css = "h2 { color: #5e5e5e; }";

    server.handle("/", [&style_css](const request &req, const response &res) {

        auto body = loading_templete("../static/index.html", res);

	boost::system::error_code ec;
	auto push = res.push(ec, "GET", "/style.css");

	push -> write_head(200, {{"Content-Type", {"text/css"}}});
	push -> end(style_css);

        if (!body) {
            res.write_head(404);
            res.end();
        }

	std::cout << "some one find me!\n" << std::endl;

        res.write_head(200);
        res.end(body);

        // header_map mmp = req.header();

        // header_map::iterator pos;

        // for(pos = mmp.begin(); pos != mmp.end(); ++pos) {
        //     std::cout << "value for " << pos->first <<" can be " << (pos->second).value << std::endl;
        // }

        // log:
        // accept */*
        // user-agent curl/7.53.1

        // ***  another workaround *** //

        // auto headers = req.header();

        // for(const auto &header : headers) {
        //     std::cout << "value for " << header.first <<" can be " << (header.second).value << std::endl;
        // }
    });

    server.handle("/api/article/", [&rdx](const request &req, const response &res) {
        std::string article_id = getParamters(req.uri().path, 3);

        auto method = req.method();

        json data;

        data["method"] = method;
        data["request_params"] = article_id;
        // if (!article_id) {
            // json articles;
            // std::vector<std::string> tips = {"author", "content", "date"};
            // int total = stoi(rdx.get("article-count"));

            // for (int i = 0;i < total; i ++) {
            //     json article;
            //     std::string n = std::to_string(i + 1);
            //     for (const auto& tip : tips) {
            //         article[tip] = rdx.get("article-" + n + "-" + tip);
            //     }
            //     articles[i] = article;
            // }
            // data["data"] = articles;
            // data["total"] = rdx.get("article-count");
            // data["msg"] = "hello " + rdx.get("hello");
        // }

        // data["article_id"] = article_id;
        // data["article_header"] = "第一个篇章";
        // data["article_info"] = {
        //     {"date", "2017/4/6"},
        //     {"author", "zH"},
        //     {"weather", "sunny"}
        // };
        // data["article_content"] = "这是unique.moe的第一篇测试用文章，也许今后不会有第二篇测试用文章了，所以请好好珍惜我！";

        header_map cors_header;

        if (method == "OPTIONS") {
            cors_header = {
                {"Access-Control-Allow-Origin", {"*"}},
                {"Access-Control-Allow-Methods", {"GET, POST, OPTIONS"}},
                {"Access-Control-Allow-Headers", {"DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range"}},
                {"Access-Control-Max-Age", {"1728000"}},
                {"Content-Type", {"text/plain charset=UTF-8"}},
                {"Content-Length", {"0"}}
            };
            res.write_head(204, cors_header);
            res.end();
        }else {
            cors_header = {
                {"Access-Control-Allow-Origin", {"*"}},
                {"Access-Control-Allow-Methods", {"GET, POST, OPTIONS"}},
                {"Access-Control-Allow-Headers", {"DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range"}},
                {"Content-Type", {"application/json"}}
            };
            res.write_head(200, cors_header);
            res.end(data.dump());
        }
    });

    std::cout << "welcome to uniquehttp2, master." << std::endl;

    if (server.listen_and_serve(ec, tls, "0.0.0.0", port)) {
        std::cout << "my http port is " << port <<" , master." << std::endl;
        std::cerr << "error: " << ec.message() << std::endl;
    }else {
        std::cout << "server.listen_and_serv has undefined." << std::endl;
    }
}


text:
#pragma once

#include <vector>
#include <functional>
#include <algorithm>
#include <numeric>
#include <queue>
#include <iostream>

#include <Eigen/Dense>

#include <array>
#include <list>
#include <stack>

namespace Discregrid
{

template <typename HullType>
class KDTree
{
public:

    using TraversalPredicate = std::function<bool (unsigned int node_index, unsigned int depth)> ;
    using TraversalCallback = std::function <void (unsigned int node_index, unsigned int depth)>;
    using TraversalPriorityLess = std::function<bool (std::array<int, 2> const& nodes)>;

    struct Node
    {
        Node(unsigned int b_, unsigned int n_)
            : children({{-1, -1}})
            , begin(b_), n(n_) {}

        Node() = default;

        bool isLeaf() const { return children[0] < 0 && children[1] < 0; }

        // Index of child nodes in nodes array.
        // -1 if child does not exist.
        std::array<int, 2> children;

        // Index according entries in entity list.
        unsigned int begin;

        // Number of owned entries.
        unsigned int n;
    };

    struct QueueItem { unsigned int n, d; };
    using TraversalQueue = std::queue<QueueItem>;

    KDTree(std::size_t n)
        : m_lst(n) {}

    virtual ~KDTree() {}

    Node const& node(unsigned int i) const { return m_nodes[i]; }
    HullType const& hull(unsigned int i) const { return m_hulls[i]; }
    unsigned int entity(unsigned int i) const { return m_lst[i]; }

    void construct();
    void update();
    void traverseDepthFirst(TraversalPredicate pred, TraversalCallback cb,
        TraversalPriorityLess const& pless = nullptr) const;
    void traverseBreadthFirst(TraversalPredicate const& pred, TraversalCallback const& cb, unsigned int start_node = 0, TraversalPriorityLess const& pless = nullptr, TraversalQueue& pending = TraversalQueue()) const;

protected:

    void construct(unsigned int node, Eigen::AlignedBox3d const& box,
        unsigned int b, unsigned int n);
    void traverseDepthFirst(unsigned int node, unsigned int depth,
        TraversalPredicate pred, TraversalCallback cb, TraversalPriorityLess const& pless) const;
    void traverseBreadthFirst(TraversalQueue& pending,
        TraversalPredicate const& pred, TraversalCallback const& cb, TraversalPriorityLess const& pless = nullptr) const;

    unsigned int addNode(unsigned int b, unsigned int n);

    virtual Eigen::Vector3d const& entityPosition(unsigned int i) const = 0;
    virtual void computeHull(unsigned int b, unsigned int n, HullType& hull) const = 0;

protected:

    std::vector<unsigned int> m_lst;

    std::vector<Node> m_nodes;
    std::vector<HullType> m_hulls;
};

#include "kd_tree.inl"
}

ext: hpp


text:
#include <fstream>
#include <vector>
#include <iterator>
#include <iostream>
#include <exception>
#include <boost/program_options.hpp>
#include <memory>

#include <openssl/ec.h>
#include <openssl/err.h>
#include "openssl/conf.h"
#include "openssl/err.h"
#include "openssl/engine.h"
#include "openssl/ssl.h"

#include "TTCN3.hh"
#include "EtsiTs103097Module.hh"
#include "EtsiTs102941MessagesCa.hh"

#include "its/utils.hh"
#include "its/itspki-debug.hh"
#include "its/itspki-session.hh"
#include "its/itspki-etsi.hh"

bool ItsPkiException::initialized = false;

ItsPkiSession::ItsPkiSession(ItsPkiInternalData &_idata)
{
	TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);
	TTCN_EncDec::clear_error();

	idata = &_idata;
}

ItsPkiSession::~ItsPkiSession()
{
        ECKey_Free(sessionTechnicalKey);
        ECKey_Free(sessionItsEcVerificationKey);
        ECKey_Free(sessionItsEcEncryptionKey);
        ECKey_Free(sessionItsAtVerificationKey);
        ECKey_Free(sessionItsAtEncryptionKey);
	OpenSSL_cleanup();
}

OCTETSTRING &
ItsPkiSession::sessionGetItsCanonicalId()
{
        DEBUGC_STREAM_CALLED;
	if (!its_cid.is_bound() || its_cid.lengthof() == 0)
		its_cid = idata->GetItsCanonicalId();

        DEBUGC_STREAM_RETURNS_OK;
	return its_cid;
}

bool
ItsPkiSession::setSKeyContext(OCTETSTRING &skey_id, OCTETSTRING &aes_key, OCTETSTRING &tag)
{
	return etsiServices.setDecryptContextWithSKey(skey_id, aes_key, tag);
};

bool
ItsPkiSession::GetPublicVerificationKey(void *ec_key, IEEE1609dot2BaseTypes::PublicVerificationKey &pubkey)
{
        int nid = -1;
        OCTETSTRING x, y;

        DEBUGC_STREAM_CALLED;
        if (!ECKey_GetPublicKeyComponents(ec_key, nid, x, y))   {
                ERROR_STREAMC << "something wrong with EC PublicKey components" << std::endl;
                return false;
        }

        if (nid == NID_X9_62_prime256v1)   {
                IEEE1609dot2BaseTypes::EccP256CurvePoint ec_point;
                ec_point.uncompressedP256().x() = x;
                ec_point.uncompressedP256().y() = y;
                pubkey.ecdsaNistP256() = ec_point;
        }
        else if (nid == NID_brainpoolP256r1)   {
                IEEE1609dot2BaseTypes::EccP256CurvePoint ec_point;
                ec_point.uncompressedP256().x() = x;
                ec_point.uncompressedP256().y() = y;
                pubkey.ecdsaBrainpoolP256r1() = ec_point;
        }
        else if (nid == NID_brainpoolP384r1)   {
                IEEE1609dot2BaseTypes::EccP384CurvePoint ec_point;
                ec_point.uncompressedP384().x() = x;
                ec_point.uncompressedP384().y() = y;
                pubkey.ecdsaBrainpoolP384r1() = ec_point;
        }
        else    {
                ERROR_STREAMC << "no support for EC curve '" << OBJ_nid2sn(nid) << "'" << std::endl;
                return false;
        }

        DEBUGC_STREAM_RETURNS_OK;
        return true;
}

bool
ItsPkiSession::GetItsEcPublicVerificationKey(IEEE1609dot2BaseTypes::PublicVerificationKey &pubkey)
{
	if (idata == NULL)
		return false;
	void *key = idata->GetItsEcVerificationKey();
	if (key == NULL)
		key = sessionItsEcVerificationKey;
	if (key == NULL)
		return false;

        return GetPublicVerificationKey(key, pubkey);
}

bool
ItsPkiSession::GetItsAtPublicVerificationKey(IEEE1609dot2BaseTypes::PublicVerificationKey &pubkey)
{
        DEBUGC_STREAM_CALLED;

	if (idata == NULL)
		return false;
	void *key = idata->GetItsAtVerificationKey();
	if (key == NULL)
		key = sessionItsAtVerificationKey;
	if (key == NULL)
		return false;

        return GetPublicVerificationKey(key, pubkey);
}

bool
ItsPkiSession::GetPublicEncryptionKey(void *ec_key, IEEE1609dot2BaseTypes::PublicEncryptionKey &pubkey)
{
        int nid = -1;
        OCTETSTRING x, y;

        DEBUGC_STREAM_CALLED;

        if (!ECKey_GetPublicKeyComponents(ec_key, nid, x, y))   {
                ERROR_STREAMC << "something wrong with EC PublicKey components" << std::endl;
                return false;
        }

        if (nid == NID_X9_62_prime256v1)   {
                IEEE1609dot2BaseTypes::EccP256CurvePoint ec_point;
                ec_point.uncompressedP256().x() = x;
                ec_point.uncompressedP256().y() = y;
                pubkey.publicKey().eciesNistP256() = ec_point;
        }
        else if (nid == NID_brainpoolP256r1)   {
                IEEE1609dot2BaseTypes::EccP256CurvePoint ec_point;
                ec_point.uncompressedP256().x() = x;
                ec_point.uncompressedP256().y() = y;
                pubkey.publicKey().eciesBrainpoolP256r1() = ec_point;
        }
        else    {
                ERROR_STREAMC << "unexpected EC curve: " << OBJ_nid2sn(nid) << std::endl;
                return false;
        }

        pubkey.supportedSymmAlg() = IEEE1609dot2BaseTypes::SymmAlgorithm::aes128Ccm;

        DEBUGC_STREAM_RETURNS_OK;
        return true;
}

bool
ItsPkiSession::GetItsEcPublicEncryptionKey(IEEE1609dot2BaseTypes::PublicEncryptionKey &pubkey)
{
	if (idata == NULL)
		return false;
	void *key = idata->GetItsEcEncryptionKey();
	if (key == NULL)
		key = sessionItsEcEncryptionKey;
	if (key == NULL)
		return false;

        return GetPublicEncryptionKey(key, pubkey);
}

bool
ItsPkiSession::GetItsAtPublicEncryptionKey(IEEE1609dot2BaseTypes::PublicEncryptionKey &pubkey)
{
        DEBUGC_STREAM_CALLED;

	if (idata == NULL)
		return false;
	void *key = idata->GetItsAtEncryptionKey();
	if (key == NULL)
		key = sessionItsAtEncryptionKey;
	if (key == NULL)
		return false;

        return GetPublicEncryptionKey(key, pubkey);
}

OCTETSTRING &
ItsPkiSession::sessionGetItsEcCert()
{
	if (idata != NULL && idata->GetItsEcCertBlob().is_bound())
		return idata->GetItsEcCertBlob();
	return sessionItsEcCert;
};

OCTETSTRING &
ItsPkiSession::sessionGetItsEcId()
{
	if (idata != NULL && idata->GetItsEcId().is_bound())
		return idata->GetItsEcId();
	return sessionItsEcId;
};

bool
ItsPkiSession::GetIEEE1609dot2Signature(ItsPkiInternalData &idata, OCTETSTRING &data, OCTETSTRING &signer, void *key,
		IEEE1609dot2BaseTypes::Signature &out_signature)
{
	DEBUGC_STREAM_CALLED;

	if (key == NULL)   {
		ERROR_STREAMC << "invalid argument: no key" << std::endl;
		return false;
	}

	OCTETSTRING key_id;
	if (!ECKey_PublicKeyHashedID(key, key_id))   {
		ERROR_STREAMC << "Cannot get Key ID" << std::endl;
		return false;
	}
	DEBUGC_STREAM << "Signer Key: '" << oct2str(key_id) << "'" << std::endl;

	int nid = ECKey_GetNid(key);

	OCTETSTRING rSig, sSig;
	if (!IEEE1609dot2_Sign(data, signer, key, rSig, sSig))   {
		ERROR_STREAMC << "Signature failed" << std::endl;
		return false;
	}

	dump_ttcn_object(rSig, "Signature::rSig: ");
	dump_ttcn_object(sSig, "Signature::sSig: ");

	DEBUGC_STREAM << "nid '" << OBJ_nid2sn(nid) << "'" << std::endl;
	if (nid == NID_X9_62_prime256v1)   {
                IEEE1609dot2BaseTypes::EccP256CurvePoint curve_point;
                curve_point.x__only() = rSig;

                IEEE1609dot2BaseTypes::EcdsaP256Signature signature;
                signature.rSig() = curve_point;
                signature.sSig() = sSig;

		out_signature.ecdsaNistP256Signature() = signature;
	}
	else if (nid == NID_brainpoolP256r1)  {
                IEEE1609dot2BaseTypes::EccP256CurvePoint curve_point;
                curve_point.x__only() = rSig;

                IEEE1609dot2BaseTypes::EcdsaP256Signature signature;
                signature.rSig() = curve_point;
                signature.sSig() = sSig;

		out_signature.ecdsaBrainpoolP256r1Signature() = signature;
	}
	else if (nid == NID_brainpoolP384r1)   {
                IEEE1609dot2BaseTypes::EccP384CurvePoint curve_point;
                curve_point.x__only() = rSig;

                IEEE1609dot2BaseTypes::EcdsaP384Signature signature;
                signature.rSig() = curve_point;
                signature.sSig() = sSig;

		out_signature.ecdsaBrainpoolP384r1Signature() = signature;
	}
	else   {
		ERROR_STREAMC << "non supported EC curve '" << OBJ_nid2sn(nid) << "'"  << std::endl;
		return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::IEEE1609dot2_VerifyToBeEncoded(OCTETSTRING &data, OCTETSTRING &signer, void *key,
                OCTETSTRING &rSig, OCTETSTRING &sSig)
{
        DEBUGC_STREAM_CALLED;

	OCTETSTRING key_id;
	if (!ECKey_PublicKeyHashedID(key, key_id))   {
		ERROR_STREAMC << "Cannot get Key ID" << std::endl;
		return false;
	}
	DEBUGC_STREAM << "Verify Key: '" << oct2str(key_id) << "'" << std::endl;

        switch (idata->GetHashAlgorithm())   {
        case IEEE1609dot2BaseTypes::HashAlgorithm::sha256:
		if (!IEEE1609dot2_VerifyWithSha256(key, rSig, sSig, data, signer))  {
                        ERROR_STREAMC << "IEEE1609dot2 SHA256 verify failed" << std::endl;
                        return false;
                }
                break;
        case IEEE1609dot2BaseTypes::HashAlgorithm::sha384:
		if (!IEEE1609dot2_VerifyWithSha384(key, rSig, sSig, data, signer))  {
                        ERROR_STREAMC << "IEEE1609dot2 SHA384 verify failed" << std::endl;
                        return false;
                }
                break;
        default:
                ERROR_STREAMC << "Unsupporteds hash algorithm" << idata->GetHashAlgorithm() << std::endl;
                return false;
        }

        DEBUGC_STREAM_RETURNS_OK;
        return true;
}

bool
ItsPkiSession::IEEE1609dot2_VerifySignedData(IEEE1609dot2::SignedData &signed_data, void *key,
		IEEE1609dot2::SignedDataPayload &ret_payload)
{
        DEBUGC_STREAM_CALLED;

	OCTETSTRING sSig, rSig;
	IEEE1609dot2BaseTypes::Signature signature = signed_data.signature__();
	if (signature.ischosen(IEEE1609dot2BaseTypes::Signature::ALT_ecdsaNistP256Signature))   {
		sSig = signature.ecdsaNistP256Signature().sSig();
		if (signature.ecdsaNistP256Signature().rSig().ischosen(IEEE1609dot2BaseTypes::EccP256CurvePoint::ALT_x__only))   {
			rSig = signature.ecdsaNistP256Signature().rSig().x__only();
		}
		else {
        		ERROR_STREAMC << "not supported EccP256CurvePoint type other then ALT_x__only" << std::endl;
			return false;
		}
	}
	else if (signature.ischosen(IEEE1609dot2BaseTypes::Signature::ALT_ecdsaBrainpoolP256r1Signature))   {
		sSig = signature.ecdsaBrainpoolP256r1Signature().sSig();
		if (signature.ecdsaBrainpoolP256r1Signature().rSig().ischosen(IEEE1609dot2BaseTypes::EccP256CurvePoint::ALT_x__only))   {
			rSig = signature.ecdsaBrainpoolP256r1Signature().rSig().x__only();
		}
		else {
        		ERROR_STREAMC << "not supported EccP256CurvePoint type other then ALT_x__only" << std::endl;
			return false;
		}
	}
	else   {
        	ERROR_STREAMC << "not supported Signature type : " << signature.get_selection() << std::endl;
		return false;
	}

	IEEE1609dot2::ToBeSignedData tbs_data = signed_data.tbsData();
        OCTETSTRING tbs_encoded;
	if (!encToBeSignedData(tbs_data, tbs_encoded))   {
	       	ERROR_STREAMC << "cannot encode ToBeSignedData" << std::endl;
		return false;
	}

	OCTETSTRING signer_encoded;
	if (signed_data.signer().ischosen(IEEE1609dot2::SignerIdentifier::ALT_self__))   {
		signer_encoded = OCTETSTRING(0, NULL);
	}
	else if (signed_data.signer().ischosen(IEEE1609dot2::SignerIdentifier::ALT_digest))  {
		if (idata->GetEAId() == signed_data.signer().digest())   {
			signer_encoded = idata->GetEACertBlob();
		}
		else if (idata->GetAAId() == signed_data.signer().digest())   {
			signer_encoded = idata->GetAACertBlob();
		}
		else if (idata->GetItsEcId() == signed_data.signer().digest())   {
			signer_encoded = idata->GetItsEcCertBlob();
		}
		else   {
	       		ERROR_STREAMC << "Expected to be signed by EA or by AA" << std::endl;
			return false;
		}

		if (!idata->getVerificationKeyFromCertificate(signer_encoded, &key))   {
	       		ERROR_STREAMC << "Cannot get verification key from certificate" << std::endl;
			return false;
		}
	}
	else   {
	       	ERROR_STREAMC << "verify with signer other the 'self' do not implemented" << std::endl;
		return false;
	}

	if (key == NULL)   {
		ERROR_STREAMC << "No key to verify signature" << std::endl;
		return false;
	}

	if (!IEEE1609dot2_VerifyToBeEncoded(tbs_encoded, signer_encoded, key, rSig, sSig))  {
                ERROR_STREAMC << "Cannot verify signature" << std::endl;
                return false;
	}

	ret_payload = tbs_data.payload();

	DEBUGC_STREAM_RETURNS_OK;
        return true;
}

bool
ItsPkiSession::IEEE1609dot2_VerifySignedData_C(IEEE1609dot2::SignedData &signed_data, void *key,
		IEEE1609dot2::Ieee1609Dot2Content &ret_content)
{
        DEBUGC_STREAM_CALLED;

	IEEE1609dot2::SignedDataPayload payload;
	if (!IEEE1609dot2_VerifySignedData(signed_data, key, payload))   {
                ERROR_STREAMC << "cannot verify signed data" << std::endl;
                return false;
	}

	if (payload.data().is_present())   {
		IEEE1609dot2::Ieee1609Dot2Data data = payload.data();
		if (data.protocolVersion() != Ieee1609Dot2Data_ProtocolVersion)   {
                	ERROR_STREAMC << "Unsupported Ieee1609Dot2Data ProtocolVersion : " << data.protocolVersion() << std::endl;
                	return false;
		}
		ret_content = data.content();
	}
	else   {
                ERROR_STREAMC << "expected SignedData payload" << std::endl;
                return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
        return true;
}

bool
ItsPkiSession::IEEE1609dot2_VerifySignedData_H(IEEE1609dot2::SignedData &signed_data, void *key,
		IEEE1609dot2::HashedData &ret_extDataHash)
{
        DEBUGC_STREAM_CALLED;

	IEEE1609dot2::SignedDataPayload payload;
	if (!IEEE1609dot2_VerifySignedData(signed_data, key, payload))   {
                ERROR_STREAMC << "cannot verify signed data" << std::endl;
                return false;
	}

	if (payload.extDataHash().is_present()) {
		ret_extDataHash = payload.extDataHash();
	}
	else   {
                ERROR_STREAMC << "expected SignedData ExtDataHash" << std::endl;
                return false;
	}

        DEBUGC_STREAM_RETURNS_OK;
        return true;
}

bool
ItsPkiSession::EcEnrollmentRequest_InnerEcRequest(ItsPkiInternalData &idata, EtsiTs102941TypesEnrolment::InnerEcRequest &inner_ec_request)
{
	DEBUGC_STREAM_CALLED;

	OCTETSTRING cid = sessionGetItsCanonicalId();
	if (!cid.is_bound() || cid.is_bound() == 0)   {
		ERROR_STREAMC << "failed: ITS Canonical ID is not set" << std::endl;
		return false;
	}

	if (!idata.EcCheckAidSsp())   {
		ERROR_STREAMC << "invalid EC permissions" << std::endl;
		return false;
	}

	// IEEE1609dot2BaseTypes::SequenceOfPsidSsp ssp_seq = idata.EcGetAppPermsSsp();
	// requestedSubjectAttributes := { id := omit, validityPeriod := omit, region := omit, assuranceLevel := omit,
	// 	appPermissions := { { psid := 0, ssp := { bitmapSsp := ''O } } },
	// 	certIssuePermissions := omit }

	IEEE1609dot2BaseTypes::Duration duration = idata.GetItsEcCertDuration();
	INTEGER valid_from = idata.GetItsEcCertValidFrom();
	if (valid_from == 0)
		valid_from = timeNow_InSec();
	IEEE1609dot2BaseTypes::ValidityPeriod validity_period = IEEE1609dot2BaseTypes::ValidityPeriod(valid_from, duration);

	EtsiTs102941BaseTypes::CertificateSubjectAttributes cert_attrs;
	cert_attrs.id() = OMIT_VALUE;
	cert_attrs.validityPeriod() = validity_period;
	cert_attrs.region() = OMIT_VALUE;
	cert_attrs.assuranceLevel() = OMIT_VALUE;
	cert_attrs.appPermissions() = idata.EcGetAppPermsSsp();
	cert_attrs.certIssuePermissions() = OMIT_VALUE;

	// verificationKey := { ecdsaNistP256 := { uncompressedP256 := { x := ''O, y := ''O } } },
	IEEE1609dot2BaseTypes::PublicVerificationKey verif_pubkey;
	if (!GetPublicVerificationKey(sessionGetItsEcVerificationKey(), verif_pubkey))   {
		ERROR_STREAMC << "cannot get Ec PublicVerificationKey: " << std::endl;
		return false;
	}

	EtsiTs102941BaseTypes::PublicKeys pubkeys = EtsiTs102941BaseTypes::PublicKeys(verif_pubkey, OMIT_VALUE);

	// encryptionKey := { supportedSymmAlg := aes128Ccm (0), publicKey := { eciesNistP256 := { uncompressedP256 := { x := ''O, y := ''O } } } }
	if (sessionGetItsEcEncryptionKey() != NULL)   {
		IEEE1609dot2BaseTypes::PublicEncryptionKey encryption_pubkey;
		if (!GetPublicEncryptionKey(sessionGetItsEcEncryptionKey(), encryption_pubkey))   {
			ERROR_STREAMC << "cannot get Ec PublicEncryptionKey: " << std::endl;
			return false;
		}

		pubkeys.encryptionKey() = encryption_pubkey;
	}

	//  InnerEcRequest := { itsId := "", certificateFormat := 1, publicKeys := { verificationKey := { ... }, encryptionKey := { ... } }, requestedSubjectAttributes := { ... } }
	inner_ec_request = EtsiTs102941TypesEnrolment::InnerEcRequest( cid, ItsPkiInternalData::CertificateFormat::ts103097v131, pubkeys, cert_attrs);

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

INTEGER
ItsPkiSession::timeNow_InSec()
{
	struct tm tm_tm = {0, 0, 0, 1, 0, 2004 - 1900, 0, 0, 0}, lt = {0};
	time_t t = time(NULL);
	localtime_r(&t, &lt);

	int now = (t - lt.tm_gmtoff - mktime(&tm_tm));
	return INTEGER(now);
}

INTEGER
ItsPkiSession::timeNow_InMkSec()
{
	INTEGER now = timeNow_InSec();
	now.set_long_long_val((long long int)(now) * 1000000l);
	return now;
}

bool
ItsPkiSession::EcEnrollmentRequest_HeaderInfo(ItsPkiInternalData &idata, IEEE1609dot2::HeaderInfo &header_info)
{
	DEBUGC_STREAM_CALLED;

	// printf("%s +%i: ########## TODO TAI clock ##########\n", __FILE__, __LINE__);
	INTEGER time_now = timeNow_InMkSec();
	header_info = IEEE1609dot2::HeaderInfo(
			INTEGER(ITS_APP_NAME_SECURED_CERT_REQUEST),
			time_now,
			OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE );

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::EcEnrollmentRequest_InnerData(ItsPkiInternalData &idata,
		EtsiTs102941TypesEnrolment::InnerEcRequest &inner_request,
		IEEE1609dot2::Ieee1609Dot2Data &inner_data)
{
	DEBUGC_STREAM_CALLED;

	OCTETSTRING inner_ec_request_encoded;
	encInnerEcRequest(inner_request, inner_ec_request_encoded);

	IEEE1609dot2::Ieee1609Dot2Content inner_dot_content;
	inner_dot_content.unsecuredData() = inner_ec_request_encoded;
	inner_dot_content.unsecuredData().set_opaque(&inner_request);

	// data := { protocolVersion := 3, content := { unsecuredData := { ... } } }
	IEEE1609dot2::Ieee1609Dot2Data inner_dot_data = IEEE1609dot2::Ieee1609Dot2Data(Ieee1609Dot2Data_ProtocolVersion, inner_dot_content);
	// payload := { data := { ... }, extDataHash := omit }
	IEEE1609dot2::SignedDataPayload	signed_payload = IEEE1609dot2::SignedDataPayload(inner_dot_data, OMIT_VALUE);

	// headerInfo := { psid := 0, generationTime := 0l,
	// 	expiryTime := omit, generationLocation := omit, p2pcdLearningRequest := omit, missingCrlIdentifier := omit, encryptionKey := omit,
	// 	inlineP2pcdRequest := omit, requestedCertificate := omit }
	IEEE1609dot2::HeaderInfo header_info;
	if (!EcEnrollmentRequest_HeaderInfo(idata, header_info))   {
		ERROR_STREAMC << "cannot build HeaderInfo" << std::endl;
		return false;
	}

	// tbsData := { payload := { ... }, headerInfo  := { ... } }
	IEEE1609dot2::ToBeSignedData tbs = IEEE1609dot2::ToBeSignedData(signed_payload, header_info);
	OCTETSTRING tbs_encoded;
	if (!encToBeSignedData(tbs, tbs_encoded))  {
		ERROR_STREAMC << "cannot encode ToBeSigned" << std::endl;
		return false;
	}

	dump_ttcn_object(tbs_encoded, "To be signed by ITS Ec Verification Key (encoded): ");
	IEEE1609dot2BaseTypes::HashAlgorithm hash_algo = idata.GetHashAlgorithm();
	IEEE1609dot2::SignerIdentifier signer_id;
	signer_id.self__() = ASN_NULL(ASN_NULL_VALUE);

	// signature_ := { ecdsaNistP256Signature := { rSig := { x_only := ''O }, sSig := ''O } }
	IEEE1609dot2BaseTypes::Signature signature;
	if (!GetIEEE1609dot2Signature(idata, tbs_encoded, sessionGetItsEcCert(), sessionGetItsEcVerificationKey(), signature))   {
		ERROR_STREAMC << "signing failed" << std::endl;
		return false;
	}

	// signedData := { hashId := sha256 (0), tbsData := { ... }, signer := { self := NULL }, signature_ := { ... } }
	IEEE1609dot2::SignedData inner_sdata;
	inner_sdata.hashId() = hash_algo;
	inner_sdata.tbsData() = tbs;
	inner_sdata.signer() = signer_id;
	inner_sdata.signature__() = signature;

	// content := { signedData := { ... } }
	IEEE1609dot2::Ieee1609Dot2Content inner_content;
	inner_content.signedData() = inner_sdata;

	// enrolmentRequest := { protocolVersion := 3, content := { signedData := { ...  } } }
	inner_data = IEEE1609dot2::Ieee1609Dot2Data(Ieee1609Dot2Data_ProtocolVersion, inner_content);

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::EncryptSignedData_ForEa(ItsPkiInternalData &idata, OCTETSTRING &tbe,
		IEEE1609dot2::Ieee1609Dot2Data &ret_encrypted)
{
	DEBUGC_STREAM_CALLED;

	OCTETSTRING cert_blob = idata.GetEACertBlob();
	if (cert_blob.lengthof() == 0)   {
		ERROR_STREAMC << "invalid EA recipient's certificate blob" << std::endl;
		return false;
	}

	OCTETSTRING rr;
	if (!etsiServices.setRecipient(cert_blob, NULL))   {
                ERROR_STREAMC << "cannot setup EncryptFor context" << std::endl;
		return false;
	}
	if (!etsiServices.GetRecipientHashedID8(rr))   {
                ERROR_STREAMC << "cannot setup EncryptFor context" << std::endl;
		return false;
	}

	// data-encrypted := { protocolVersion := 3, content := { encryptedData := {
	// 	recipients := { { certRecipInfo := { recipientId := ''O, encKey := { eciesNistP256 := { v := { compressed_y_0 := ''O }, c := ''O, t := ''O } } } } },
	// 	ciphertext := { aes128ccm := { nonce := ''O, ccmCiphertext := ''O } }
	// } } }
	EtsiTs103097Module::EtsiTs103097Data__Encrypted__My data_encrypted;
	if (!etsiServices.EncryptPayload(tbe, data_encrypted))   {
                ERROR_STREAMC << "failed to encrypt payload" << std::endl;
		return false;
	}
	else if (!data_encrypted.is_bound())   {
                ERROR_STREAMC << "cannot encode encrypted payload" << std::endl;
		return false;
	}
	dump_ttcn_object(data_encrypted, "Data Encrypted': ");

	ret_encrypted = data_encrypted;

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::EncryptSignedData_ForEa(ItsPkiInternalData &idata, OCTETSTRING &tbe, OCTETSTRING &ret_encrypted)
{
	DEBUGC_STREAM_CALLED;

	IEEE1609dot2::Ieee1609Dot2Data data_encrypted;
	if (!EncryptSignedData_ForEa(idata, tbe, data_encrypted))   {
		ERROR_STREAMC << "failed to encrypt signed data for EA" << std::endl;
		return false;
	}

	if (!encIeee1609Dot2Data(data_encrypted, ret_encrypted))   {
		ERROR_STREAMC << "failed to encode IEEE1609dot2::Ieee1609Dot2Data for EA" << std::endl;
		return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::EncryptSignedData_ForAa(ItsPkiInternalData &idata, OCTETSTRING &tbe, OCTETSTRING &ret_encrypted)
{
	return false;
}

bool
ItsPkiSession::EncryptSignedData_ForAa(ItsPkiInternalData &idata, OCTETSTRING &tbe, IEEE1609dot2::Ieee1609Dot2Data &ret_encrypted)
{
	DEBUGC_STREAM_CALLED;

	OCTETSTRING cert_blob = idata.GetAACertBlob();

	if (!etsiServices.setRecipient(cert_blob, NULL))   {
                ERROR_STREAMC << "cannot setup EncryptFor AA context" << std::endl;
		return false;
	}

	EtsiTs103097Module::EtsiTs103097Data__Encrypted__My data_encrypted;
	if (!etsiServices.EncryptPayload(tbe, data_encrypted))   {
                ERROR_STREAMC << "failed to encrypt payload for AA" << std::endl;
		return false;
	}
	else if (!data_encrypted.is_bound())   {
                ERROR_STREAMC << "failed to encrypt payload for AA" << std::endl;
		return false;
	}

	ret_encrypted = data_encrypted;
	dump_ttcn_object(ret_encrypted, "returns data 'encrypted for': ");

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::EcEnrollmentResponse_Parse(OCTETSTRING &recipient_cert, OCTETSTRING &response_raw, OCTETSTRING &ret_cert)
{
	if (!etsiServices.setRecipient(recipient_cert, NULL))   {
		ERROR_STREAMC << "cannot setup Ec Enrollment Parse Response context" << std::endl;
		return false;
	}

	return EcEnrollmentResponse_Parse(response_raw, ret_cert);
}

bool
ItsPkiSession::EcEnrollmentResponse_Parse(OCTETSTRING &response_raw, OCTETSTRING &ret_cert)
{
	if (!EcEnrollmentResponse_Parse(response_raw))
		return false;

	ret_cert = sessionItsEcCert;
	return true;
}

/*
 * TODO: initialized sessionItsEcCert and sessionItsEcId have an impacto onto the not first EC enrollment
 */
bool
ItsPkiSession::EcEnrollmentResponse_Parse(OCTETSTRING &response_raw)
{
	DEBUGC_STREAM_CALLED;

	dump_ttcn_object(response_raw, "EcEnrollment Response: ");
	OCTETSTRING payload;
	if (!etsiServices.DecryptPayload(response_raw, payload))   {
                ERROR_STREAMC << "decrypt payload failed" << std::endl;
                return false;
	}

	EtsiTs103097Module::EtsiTs103097Data__Signed__My response_data_signed = decEtsiTs103097DataSigned(payload);
	dump_ttcn_object(response_data_signed, "EtsiTs103097Module::EtsiTs103097DataSigned response: ");

	IEEE1609dot2::Ieee1609Dot2Content content;
	if (!IEEE1609dot2_VerifySignedData_C(response_data_signed.content().signedData(), NULL, content))   {
                ERROR_STREAMC << "Cannot verify Signed Data signature" << std::endl;
                return false;
	}
	else if (!content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_unsecuredData))  {
        	ERROR_STREAMC << "expected data type 'Ieee1609Dot2Content::ALT_unsecuredData'" << std::endl;
		return false;
	}
	dump_ttcn_object(content, "Signed data content: ");

	OCTETSTRING inner_unsecured_data = content.unsecuredData();
	EtsiTs102941MessagesCa::EtsiTs102941Data response_inner_data = decEtsiTs102941Data(inner_unsecured_data);
	dump_ttcn_object(response_inner_data, "Response data: ");

	if (!response_inner_data.content().ischosen(EtsiTs102941MessagesCa::EtsiTs102941DataContent::ALT_enrolmentResponse))  {
        	ERROR_STREAMC << "invalid choice" << std::endl;
		return false;
	}
	else if (response_inner_data.content().enrolmentResponse().responseCode() != EtsiTs102941TypesEnrolment::EnrolmentResponseCode::ok)   {
        	ERROR_STREAMC << "enrollment failed with status code '" << response_inner_data.content().enrolmentResponse().responseCode() << "'" << std::endl;
		return false;
	}

	EtsiTs103097Module::EtsiTs103097Certificate cert = response_inner_data.content().enrolmentResponse().certificate();
	dump_ttcn_object(cert, "ITS EC Certificate: ");

	if (!encEtsiTs103097Certificate(cert, sessionItsEcCert))    {
        	ERROR_STREAMC << "cannot encode EtsiTs103097Certificate" << std::endl;
		return false;
	}
	else if (!getEtsiTs103097CertId(sessionItsEcCert, sessionItsEcId))   {
        	ERROR_STREAMC << "cannot set EtsiTs103097Certificate ID" << std::endl;
		return false;
	}

	dump_ttcn_object(sessionItsEcCert, "ITS EC Certificate (encoded): ");

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::EcEnrollmentResponse_Status(OCTETSTRING &response_raw)
{
	DEBUGC_STREAM_CALLED;

	OCTETSTRING payload;
	if (!etsiServices.DecryptPayload(response_raw, payload))   {
        	ERROR_STREAMC << "cannot decrypt payload" << std::endl;
		return false;
	}

	EtsiTs103097Module::EtsiTs103097Data__Signed__My data_signed = decEtsiTs103097DataSigned(payload);
	IEEE1609dot2::Ieee1609Dot2Content content;
	if (!IEEE1609dot2_VerifySignedData_C(data_signed.content().signedData(), NULL, content))   {
                ERROR_STREAMC << "Cannot verify Signed Data signature" << std::endl;
                return false;
	}
	else if (!content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_unsecuredData))  {
        	ERROR_STREAMC << "expected data type 'Ieee1609Dot2Content::ALT_unsecuredData'" << std::endl;
		return false;
	}
	dump_ttcn_object(content, "Signed data content: ");

	EtsiTs102941MessagesCa::EtsiTs102941Data inner_data = decEtsiTs102941Data(content.unsecuredData());
	if (!inner_data.content().ischosen(EtsiTs102941MessagesCa::EtsiTs102941DataContent::ALT_enrolmentResponse))   {
        	ERROR_STREAMC << "expected 'EnrollmentResponse' inner data type " << std::endl;
		return false;
	}

	EtsiTs102941TypesEnrolment::EnrolmentResponseCode respCode = inner_data.content().enrolmentResponse().responseCode();
	if (respCode != EtsiTs102941TypesEnrolment::EnrolmentResponseCode::ok)   {
        	ERROR_STREAMC << "expected response code 'OK', received '" << respCode.enum_to_str(respCode) << "'" << std::endl;
		return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::EcEnrollmentRequest_Parse(OCTETSTRING &request_raw, void *recipient_prvkey, EtsiTs102941TypesEnrolment::InnerEcRequest &inner_ec_request)
{
	DEBUGC_STREAM_CALLED;

	if (!etsiServices.setDecryptContext(recipient_prvkey, NULL))   {
                ERROR_STREAMC << "Cannot set EC enrollment 'Request Parse' context" << std::endl;
                return false;
	}

	OCTETSTRING payload;
	if (!etsiServices.DecryptPayload(request_raw, payload))   {
                ERROR_STREAMC << "decrypt payload failed" << std::endl;
                return false;
	}

	EtsiTs103097Module::EtsiTs103097Data__Signed__My request_data_signed = decEtsiTs103097DataSigned(payload);
	dump_ttcn_object(request_data_signed, "Signed request: ");

	IEEE1609dot2::Ieee1609Dot2Content content;
	if (!IEEE1609dot2_VerifySignedData_C(request_data_signed.content().signedData(), sessionGetTechnicalKey(), content))   {
                ERROR_STREAMC << "Cannot verify Signed Data signature" << std::endl;
                return false;
	}
	else if (!content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_unsecuredData))  {
        	ERROR_STREAMC << "expected data type 'Ieee1609Dot2Content::ALT_unsecuredData'" << std::endl;
		return false;
	}

	EtsiTs102941MessagesCa::EtsiTs102941Data inner_data;
	try   {
		EtsiTs102941MessagesCa::EtsiTs102941Data_decoder(content.unsecuredData(), inner_data, "OER");
	}
	catch (const TC_Error& tc_error) {
        	ERROR_STREAMC << "cannot decode Ec Enrollment inner-data" << std::endl;
		return false;
	}

	dump_ttcn_object(inner_data, "Inner request data: ");
	if (!inner_data.content().ischosen(EtsiTs102941MessagesCa::EtsiTs102941DataContent::ALT_enrolmentRequest))  {
        	ERROR_STREAMC << "expected data type 'EtsiTs102941DataContent::ALT_enrolmentRequest'" << std::endl;
		return false;
	}

	IEEE1609dot2::Ieee1609Dot2Data enrolment_request = inner_data.content().enrolmentRequest();
	dump_ttcn_object(enrolment_request, "EC enrolment request: ");
	if (enrolment_request.protocolVersion() != Ieee1609Dot2Data_ProtocolVersion)   {
        	ERROR_STREAMC << "Invalid inner data protocol version: " << enrolment_request.protocolVersion() << std::endl;
		return false;
	}
	if (!enrolment_request.content().ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_signedData))  {
        	ERROR_STREAMC << "Expected type 'Ieee1609Dot2Content::ALT_signedData'" << std::endl;
		return false;
	}
	IEEE1609dot2::SignedData signed_data = enrolment_request.content().signedData();
	dump_ttcn_object(signed_data, "Signed Data: ");

	if (!IEEE1609dot2_VerifySignedData_C(signed_data, sessionGetItsEcVerificationKey(), content))   {
                ERROR_STREAMC << "Cannot verify Signed Data signature" << std::endl;
                return false;
	}
	else if (!content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_unsecuredData))  {
        	ERROR_STREAMC << "expected data type 'Ieee1609Dot2Content::ALT_unsecuredData'" << std::endl;
		return false;
	}

	try   {
		EtsiTs102941TypesEnrolment::InnerEcRequest_decoder(content.unsecuredData(), inner_ec_request, "OER");
	}
	catch (const TC_Error& tc_error) {
        	ERROR_STREAMC << "cannot decode InnerEcRequest data" << std::endl;
		return false;
	}
	dump_ttcn_object(inner_ec_request, "Inner EC request: ");

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::IEEE1609dot2_Sign(OCTETSTRING &data, OCTETSTRING &signer,
                void *key,
                OCTETSTRING &rSig, OCTETSTRING &sSig)
{
        DEBUGC_STREAM_CALLED;

        switch (idata->GetHashAlgorithm())   {
        case IEEE1609dot2BaseTypes::HashAlgorithm::sha256:
                if (!IEEE1609dot2_SignWithSha256(data, signer, key, rSig, sSig))   {
                        ERROR_STREAMC << "IEEE1609dot2 SHA256 signature failed" << std::endl;
                        return false;
                }
                break;
        case IEEE1609dot2BaseTypes::HashAlgorithm::sha384:
                if (!IEEE1609dot2_SignWithSha384(data, signer, key, rSig, sSig))   {
                        ERROR_STREAMC << "IEEE1609dot2 SHA384 signature failed" << std::endl;
                        return false;
                }
                break;
        default:
                ERROR_STREAMC << "Unsupporteds hash algorithm" << idata->GetHashAlgorithm() << std::endl;
                return false;
        }

        DEBUGC_STREAM_RETURNS_OK;
        return true;
}

void *
ItsPkiSession::sessionGetTechnicalKey()
{
	if (idata == NULL)
		return NULL;

	if (idata->GetItsTechnicalKey() != NULL)
		return idata->GetItsTechnicalKey();

	return sessionTechnicalKey;
}

void *
ItsPkiSession::sessionGetItsEcVerificationKey()
{
	if (idata == NULL)
		return NULL;

	if (idata->GetItsEcVerificationKey() != NULL)
		return idata->GetItsEcVerificationKey();

	return sessionItsEcVerificationKey;
}

void *
ItsPkiSession::sessionGetItsEcEncryptionKey()
{
	if (idata == NULL)
		return NULL;

	if (idata->GetItsEcEncryptionKey() != NULL)
		return idata->GetItsEcEncryptionKey();

	return sessionItsEcEncryptionKey;
}

void *
ItsPkiSession::sessionGetItsAtVerificationKey()
{
	if (idata == NULL)
		return NULL;

	if (idata->GetItsAtVerificationKey() != NULL)
		return idata->GetItsAtVerificationKey();

	return sessionItsAtVerificationKey;
}

void *
ItsPkiSession::sessionGetItsAtEncryptionKey()
{
	if (idata == NULL)
		return NULL;

	if (idata->GetItsAtEncryptionKey() != NULL)
		return idata->GetItsAtEncryptionKey();
	return sessionItsAtEncryptionKey;
}

bool
ItsPkiSession::sessionCheckEcEnrollmentArguments(ItsPkiInternalData &idata)
{
	DEBUGC_STREAM_CALLED;

	if (sessionGetTechnicalKey() == NULL)   {
		ERROR_STREAMC << "ItsPkiSession::sessionCheckEcEnrollmentArguments() no ITS Technical Key" << std::endl;
		return false;
	}

	if (!idata.CheckEcEnrollmentArguments())   {
		ERROR_STREAMC << "ItsPkiSession::sessionCheckEcEnrollmentArguments() invalid internal EC enrollment request data" << std::endl;
		return false;
	}

	if ((sessionItsEcVerificationKey == NULL) && (idata.GetItsEcVerificationKey() == NULL))   {
		sessionItsEcVerificationKey = ECKey_GeneratePrivateKey();
		if (sessionItsEcVerificationKey == NULL)   {
			ERROR_STREAMC << "ItsPkiSession::sessionCheckEcEnrollmentArguments() cannot generaete EC Verification key" << std::endl;
			return false;
		}
	}

	if ((sessionItsEcEncryptionKey == NULL) && (idata.GetItsEcEncryptionKey() == NULL) && idata.IsItsEcEncryptionKeyEnabled())   {
		sessionItsEcEncryptionKey = ECKey_GeneratePrivateKey();
       		if (sessionItsEcEncryptionKey == NULL)   {
			ERROR_STREAMC << "ItsPkiSession::sessionCheckEcEnrollmentArguments() cannot generaete EC Encryption key" << std::endl;
			return false;
		}
	}

	// if (!sessionGetCanonicalId(idata).is_bound() || sessionGetCanonicalId(idata).lengthof() == 0)   {
	if (!sessionGetItsCanonicalId().is_bound() || sessionGetItsCanonicalId().lengthof() == 0)   {
		ERROR_STREAMC << "ItsPkiSession::sessionCheckEcEnrollmentArguments() cannot get session ITS Canonical ID" << std::endl;
		return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::EcEnrollmentRequest_Create(ItsPkiInternalData &idata, OCTETSTRING &request_encoded)
{
	DEBUGC_STREAM_CALLED;

	if (!sessionCheckEcEnrollmentArguments(idata))   {
		ERROR_STREAMC << "ItsPkiSession::EcEnrollmentRequest_Create() invalid Ec session data" << std::endl;
		return false;
	}

	// InnerEcRequest
	EtsiTs102941TypesEnrolment::InnerEcRequest inner_ec_request;
	EcEnrollmentRequest_InnerEcRequest(idata, inner_ec_request);
	dump_ttcn_object(inner_ec_request, "InnerEcRequest : ");

	// EtsiTS102941Data
	IEEE1609dot2::Ieee1609Dot2Data inner_data;
	if (!EcEnrollmentRequest_InnerData(idata, inner_ec_request, inner_data))   {
		ERROR_STREAMC << "cannot compose InnerData " << std::endl;
		return false;
	}

	EtsiTs102941MessagesCa::EtsiTs102941DataContent etsits_102941_data_content;
	etsits_102941_data_content.enrolmentRequest() = inner_data;

	EtsiTs102941MessagesCa::EtsiTs102941Data etsits_102941_data = EtsiTs102941MessagesCa::EtsiTs102941Data(EtsiTs102941Data_Version, etsits_102941_data_content);

	OCTETSTRING encoded_etsits_102941_data;
	if (!encEtsiTs102941Data(etsits_102941_data, encoded_etsits_102941_data))   {
		ERROR_STREAMC << "cannot encode EtsiTs102941MessagesCa::EtsiTs102941Data" << std::endl;
		return false;
	}

	dump_ttcn_object(etsits_102941_data, "EtsiTs102941Data : ");
	dump_ttcn_object(encoded_etsits_102941_data, "EtsiTs102941Data (encoded): ");

	IEEE1609dot2::Ieee1609Dot2Content content_for_payload;
	content_for_payload.unsecuredData() = encoded_etsits_102941_data;
	content_for_payload.unsecuredData().set_opaque(&etsits_102941_data);

	IEEE1609dot2::Ieee1609Dot2Data env_for_payload = IEEE1609dot2::Ieee1609Dot2Data(Ieee1609Dot2Data_ProtocolVersion, content_for_payload);

	IEEE1609dot2::SignedDataPayload	signed_payload = IEEE1609dot2::SignedDataPayload(env_for_payload,  OMIT_VALUE);

	IEEE1609dot2::HeaderInfo header_info;
	if (!EcEnrollmentRequest_HeaderInfo(idata, header_info))   {
		ERROR_STREAMC << "cannot compose HeaderInfo" << std::endl;
		return false;
	}

	IEEE1609dot2::ToBeSignedData tbs = IEEE1609dot2::ToBeSignedData(signed_payload, header_info);
	OCTETSTRING tbs_encoded;
	if (!encToBeSignedData(tbs, tbs_encoded))   {
		ERROR_STREAMC << "cannot encode ToBeSignedData" << std::endl;
		return false;
	}

	dump_ttcn_object(tbs, "ToBeSignedData by Technical Key: ");
	dump_ttcn_object(tbs_encoded, "ToBeSignedData Technical Key (encoded): ");

	IEEE1609dot2BaseTypes::HashAlgorithm hash_algo = idata.GetHashAlgorithm();
	IEEE1609dot2::SignerIdentifier signer_id;
	signer_id.self__() = ASN_NULL(ASN_NULL_VALUE);

	IEEE1609dot2BaseTypes::Signature signature;
	OCTETSTRING signer = OCTETSTRING(0, NULL);
	if (!GetIEEE1609dot2Signature(idata, tbs_encoded, signer, sessionGetTechnicalKey(), signature))   {
		ERROR_STREAMC << "failed to sign" << std::endl;
		return false;
	}

	// EtsiTs103097Data-Signed  (outer)
	IEEE1609dot2::SignedData outer_sdata;
	outer_sdata.hashId() = hash_algo;
	outer_sdata.tbsData() = tbs;
	outer_sdata.signer() = signer_id;
	outer_sdata.signature__() = signature;

	IEEE1609dot2::Ieee1609Dot2Content outer_content;
	outer_content.signedData() = outer_sdata;

	// EtsiTs103097Data-data  (outer)
	IEEE1609dot2::Ieee1609Dot2Data outer_data = IEEE1609dot2::Ieee1609Dot2Data(Ieee1609Dot2Data_ProtocolVersion, outer_content);
        OCTETSTRING outer_data_encoded;
	encIeee1609Dot2Data(outer_data, outer_data_encoded);

	dump_ttcn_object(outer_data, "IEEE1609dot2::Ieee1609Dot2Data : ");
	dump_ttcn_object(outer_data_encoded, "IEEE1609dot2::Ieee1609Dot2Data (encoded): ");

	if (!EncryptSignedData_ForEa(idata, outer_data_encoded, request_encoded))   {
		ERROR_STREAMC << "cannot encrypt signed data for EA" << std::endl;
		return false;
	}
	dump_ttcn_object(request_encoded, "Encrypted and encoded EC request: ");

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

// At Request
bool
ItsPkiSession::sessionCheckAtEnrollmentArguments(ItsPkiInternalData &idata)
{
	DEBUGC_STREAM_CALLED;

	if (!idata.CheckAtEnrollmentArguments())   {
		ERROR_STREAMC << "ItsPkiSession::sessionCheckAtEnrollmentArguments() invalid internal AT enrollment request data" << std::endl;
		return false;
	}

	if ((sessionItsAtVerificationKey == NULL) && (idata.GetItsAtVerificationKey() == NULL))   {
		sessionItsAtVerificationKey = ECKey_GeneratePrivateKey();
		if (sessionItsAtVerificationKey == NULL)   {
			ERROR_STREAMC << "ItsPkiSession::sessionCheckAtEnrollmentArguments() cannot generaete At Verification key" << std::endl;
			return false;
		}
	}

	if ((sessionItsAtEncryptionKey == NULL) && (idata.GetItsAtEncryptionKey() == NULL) && idata.IsItsAtEncryptionKeyEnabled())   {
		sessionItsAtEncryptionKey = ECKey_GeneratePrivateKey();
       		if (sessionItsAtEncryptionKey == NULL)   {
			ERROR_STREAMC << "ItsPkiSession::sessionCheckAtEnrollmentArguments() cannot generaete At Encryption key" << std::endl;
			return false;
		}
	}

	if (!sessionGetItsCanonicalId().is_bound() || sessionGetItsCanonicalId().lengthof() == 0)   {
		ERROR_STREAMC << "ItsPkiSession::sessionCheckEcEnrollmentArguments() cannot get session ITS Canonical ID" << std::endl;
		return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::AtEnrollmentRequest_HeaderInfo(ItsPkiInternalData &idata, IEEE1609dot2::HeaderInfo &header_info)
{
	DEBUGC_STREAM_CALLED;
	if (!EcEnrollmentRequest_HeaderInfo(idata, header_info))   {
        	ERROR_STREAMC << "cannot compose AT HeaderInfo " << std::endl;
		return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::AtEnrollmentRequest_SignedExternalPayload(ItsPkiInternalData &idata,
		EtsiTs102941TypesAuthorization::SharedAtRequest &sharedAtRequest,
		EtsiTs103097Module::EtsiTs103097Data__SignedExternalPayload &ret)
{
	DEBUGC_STREAM_CALLED;

	IEEE1609dot2::HeaderInfo header_info;
	if (!AtEnrollmentRequest_HeaderInfo(idata, header_info))   {
        	ERROR_STREAMC << "failed to compose AT HeaderInfo " << std::endl;
		return false;
	}

	OCTETSTRING sharedAtRequest_encoded;
	if (!encSharedAtRequest(sharedAtRequest, sharedAtRequest_encoded))   {
		ERROR_STREAMC << "cannot encode EtsiTs102941TypesAuthorization::SharedAtRequest" << std::endl;
		return false;
	}
	dump_ttcn_object(sharedAtRequest_encoded, "SharedAtRequest encoded: ");

	OCTETSTRING sharedAtRequest_hash;
	if (!hash_256(sharedAtRequest_encoded, sharedAtRequest_hash))   {
		ERROR_STREAMC << "cannot get hash of sharedAtRequest" << std::endl;
		return false;
	}
	dump_ttcn_object(sharedAtRequest_hash, "SharedAtRequest encoded hash: ");

	IEEE1609dot2::HashedData sharedAtRequest_hashedData;
	sharedAtRequest_hashedData.sha256HashedData() = sharedAtRequest_hash;
	dump_ttcn_object(sharedAtRequest_hashedData, "SharedAtRequest hashedData: ");

	IEEE1609dot2::SignedDataPayload	signed_payload = IEEE1609dot2::SignedDataPayload(OMIT_VALUE, sharedAtRequest_hashedData);

	IEEE1609dot2::ToBeSignedData tbs = IEEE1609dot2::ToBeSignedData(signed_payload, header_info);
	OCTETSTRING tbs_encoded;
	if (!encToBeSignedData(tbs, tbs_encoded))   {
		ERROR_STREAMC << "failed to encode ToBeSignedData" << std::endl;
		return false;
	}
	dump_ttcn_object(tbs_encoded, "ToBeSigned by ITS Ec Verification Key (encoded): ");

	IEEE1609dot2::SignerIdentifier signer_id;
	signer_id.digest() = sessionGetItsEcId();

	IEEE1609dot2BaseTypes::Signature signature;
	if (!GetIEEE1609dot2Signature(idata, tbs_encoded, sessionGetItsEcCert(), sessionGetItsEcVerificationKey(), signature))   {
		ERROR_STREAMC << "failed to sign" << std::endl;
		return false;
	}

	IEEE1609dot2::SignedData sep_sdata;
	sep_sdata.hashId() = idata.GetHashAlgorithm();
	sep_sdata.tbsData() = tbs;
	sep_sdata.signer() = signer_id;
	sep_sdata.signature__() = signature;

	IEEE1609dot2::Ieee1609Dot2Content sep_content;
	sep_content.signedData() = sep_sdata;

	ret = EtsiTs103097Module::EtsiTs103097Data__SignedExternalPayload(Ieee1609Dot2Data_ProtocolVersion, sep_content);
	dump_ttcn_object(ret, "EtsiTs103097Data__SignedExternalPayload: ");

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::AtEnrollmentRequest_POP(ItsPkiInternalData &idata,
		EtsiTs102941MessagesCa::EtsiTs102941Data &etsiTsdata,
		EtsiTs103097Module::EtsiTs103097Data__Signed__My  &ret)
{
	DEBUGC_STREAM_CALLED;

	OCTETSTRING etsiTsdata_encoded;
	if (!encEtsiTs102941Data(etsiTsdata, etsiTsdata_encoded))   {
		ERROR_STREAMC << "cannot encode EtsiTs102941MessagesCa::EtsiTs102941Data" << std::endl;
		return false;
	}

	IEEE1609dot2::Ieee1609Dot2Content dot2_content;
	dot2_content.unsecuredData() = etsiTsdata_encoded;
	dot2_content.unsecuredData().set_opaque(&etsiTsdata);

	IEEE1609dot2::Ieee1609Dot2Data dot2_data = IEEE1609dot2::Ieee1609Dot2Data(Ieee1609Dot2Data_ProtocolVersion, dot2_content);
	IEEE1609dot2::SignedDataPayload	signed_payload = IEEE1609dot2::SignedDataPayload(dot2_data, OMIT_VALUE);

	IEEE1609dot2::HeaderInfo header_info;
	if (!AtEnrollmentRequest_HeaderInfo(idata, header_info))   {
        	ERROR_STREAMC << "cannot compose AT HeaderInfo " << std::endl;
		return false;
	}

	IEEE1609dot2::ToBeSignedData tbs = IEEE1609dot2::ToBeSignedData(signed_payload, header_info);
	OCTETSTRING tbs_encoded;
	if (!encToBeSignedData(tbs, tbs_encoded))   {
		ERROR_STREAMC << "failed to encode ToBeSignedData" << std::endl;
		return false;
	}
	dump_ttcn_object(tbs_encoded, "To be signed by ITS At Verification Key (encoded): ");

	IEEE1609dot2BaseTypes::HashAlgorithm hash_algo = idata.GetHashAlgorithm();

	IEEE1609dot2::SignerIdentifier signer_id;
	signer_id.self__() = ASN_NULL(ASN_NULL_VALUE);

	IEEE1609dot2BaseTypes::Signature signature;
	OCTETSTRING signer = OCTETSTRING(0, NULL);
	if (!GetIEEE1609dot2Signature(idata, tbs_encoded, signer, sessionGetItsAtVerificationKey(), signature))   {
		ERROR_STREAMC << "failed to sign" << std::endl;
		return false;
	}

	IEEE1609dot2::SignedData signedDataContentSignedData;
	signedDataContentSignedData.hashId() = hash_algo;
	signedDataContentSignedData.tbsData() = tbs;
	signedDataContentSignedData.signer() = signer_id;
	signedDataContentSignedData.signature__() = signature;

	IEEE1609dot2::Ieee1609Dot2Content signedDataContent;
	signedDataContent.signedData() = signedDataContentSignedData;
	ret = EtsiTs103097Module::EtsiTs103097Data__Signed__My(Ieee1609Dot2Data_ProtocolVersion, signedDataContent);

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::AtEnrollmentRequest_Create(ItsPkiInternalData &idata, OCTETSTRING &ret)
{
	DEBUGC_STREAM_CALLED;

	if (!sessionCheckAtEnrollmentArguments(idata))   {
		ERROR_STREAMC << "ItsPkiSession::AtEnrollmentRequest_Create() invalid At session data" << std::endl;
		return false;
	}

	OCTETSTRING v_pubkey_encoded;
	IEEE1609dot2BaseTypes::PublicVerificationKey v_pubkey;
        if (!GetItsAtPublicVerificationKey(v_pubkey))   {
		ERROR_STREAMC << "cannot get ITS AT PublicVerificationKey" << std::endl;
		return false;
	}
	else if (!encPublicVerificationKey(v_pubkey, v_pubkey_encoded))   {
		ERROR_STREAMC << "cannot encode ITS AT PublicVerificationKey" << std::endl;
		return false;
	}

	IEEE1609dot2BaseTypes::PublicEncryptionKey e_pubkey;
	OCTETSTRING e_pubkey_encoded = OCTETSTRING(0, NULL);
	if(sessionGetItsAtEncryptionKey() != NULL)   {
		if (!GetItsAtPublicEncryptionKey(e_pubkey))   {
			ERROR_STREAMC << "cannot get ITS AT PublicEncryptionKey" << std::endl;
			return false;
		}

		if (!encPublicEncryptionKey(e_pubkey, e_pubkey_encoded))   {
			ERROR_STREAMC << "cannot encode ITS AT PublicEncryptionKey" << std::endl;
			return false;
		}
	}

	OCTETSTRING hmac = random_OCTETSTRING(SHA256_DIGEST_LENGTH);
	dump_ttcn_object(hmac, "HMAC: ");

	OCTETSTRING keyTag;
	OCTETSTRING pub_keys = v_pubkey_encoded + e_pubkey_encoded;
	dump_ttcn_object(pub_keys, "PubKeys encoded: ");

	if (!hmac_sha256(pub_keys, hmac, keyTag))   {
		ERROR_STREAMC << "failed to generate HMAC: " << std::endl;
		return false;
	}
	dump_ttcn_object(keyTag, "KeyTag: ");

	IEEE1609dot2BaseTypes::Duration duration = idata.GetItsAtCertDuration();
	INTEGER valid_from = idata.GetItsAtCertValidFrom();
	if (valid_from == 0)
		valid_from = timeNow_InSec();
	IEEE1609dot2BaseTypes::ValidityPeriod validity_period = IEEE1609dot2BaseTypes::ValidityPeriod(valid_from, duration);

        IEEE1609dot2BaseTypes::SequenceOfPsidSsp ssp_seq = idata.AtGetAppPermsSsp();

        EtsiTs102941BaseTypes::CertificateSubjectAttributes cert_attrs = EtsiTs102941BaseTypes::CertificateSubjectAttributes(
			OMIT_VALUE, validity_period, OMIT_VALUE, OMIT_VALUE, ssp_seq, OMIT_VALUE);

#if 0
	IEEE1609dot2BaseTypes::Duration duration = idata.GetItsEcCertDuration();
	INTEGER valid_from = idata.GetItsEcCertValidFrom();
	if (valid_from == 0)
		valid_from = timeNow_InSec();
	IEEE1609dot2BaseTypes::ValidityPeriod validity_period = IEEE1609dot2BaseTypes::ValidityPeriod(valid_from, duration);

	EtsiTs102941BaseTypes::CertificateSubjectAttributes cert_attrs;
	cert_attrs.id() = OMIT_VALUE;
	cert_attrs.validityPeriod() = validity_period;
	cert_attrs.region() = OMIT_VALUE;
	cert_attrs.assuranceLevel() = OMIT_VALUE;
	cert_attrs.appPermissions() = idata.EcGetAppPermsSsp();
	cert_attrs.certIssuePermissions() = OMIT_VALUE;

#endif

	EtsiTs102941TypesAuthorization::SharedAtRequest sharedAtRequest;
	sharedAtRequest.eaId() = idata.GetEAId();
	sharedAtRequest.keyTag() = keyTag;
	sharedAtRequest.certificateFormat() = ItsPkiInternalData::CertificateFormat::ts103097v131;
	sharedAtRequest.requestedSubjectAttributes() = cert_attrs;
	dump_ttcn_object(sharedAtRequest, "EtsiTs102941TypesAuthorization::SharedAtRequest: ");

	EtsiTs103097Module::EtsiTs103097Data__SignedExternalPayload signedExternalPayload;
	if (!AtEnrollmentRequest_SignedExternalPayload(idata, sharedAtRequest, signedExternalPayload))   {
                ERROR_STREAMC << "cannot create SignedExternalPayload " << std::endl;
                return false;
	}
	dump_ttcn_object(signedExternalPayload, "SignedExternalPayload : ");

	OCTETSTRING signedExternalPayload_encoded;
	if (!encSignedExternalPayload(signedExternalPayload, signedExternalPayload_encoded))   {
                ERROR_STREAMC << "cannot encode SignedExternalPayload " << std::endl;
                return false;
	}

	EtsiTs103097Module::EtsiTs103097Data__Encrypted__My signedExternalPayload_encrypted;
	if (!EncryptSignedData_ForEa(idata, signedExternalPayload_encoded, signedExternalPayload_encrypted))   {
                ERROR_STREAMC << "failed to encrypt signed data for EA" << std::endl;
		return false;
	}
	dump_ttcn_object(signedExternalPayload_encrypted, "signedExternalPayload encrypted: ");

	EtsiTs102941BaseTypes::EcSignature ec_signature;
	ec_signature.encryptedEcSignature() = signedExternalPayload_encrypted;
	dump_ttcn_object(ec_signature, "EcSignature: ");

	// InnerAtRequest { publicKeys, hmacKey, sharedAtRequest, ecSignature, ...
	EtsiTs102941TypesAuthorization::InnerAtRequest innerAtRequest;
	innerAtRequest.hmacKey() = hmac;
	innerAtRequest.sharedAtRequest() = sharedAtRequest;
	innerAtRequest.ecSignature() = ec_signature;

	innerAtRequest.publicKeys() = EtsiTs102941BaseTypes::PublicKeys(v_pubkey, OMIT_VALUE);
	if(sessionGetItsAtEncryptionKey() != NULL)
		innerAtRequest.publicKeys().encryptionKey() = e_pubkey;
	dump_ttcn_object(innerAtRequest.publicKeys(), "innerAtRequest.publicKeys: ");

	EtsiTs102941MessagesCa::EtsiTs102941DataContent atDataContent;
	atDataContent.authorizationRequest() = innerAtRequest;

	// EtsiTs102941Data { InnerAtRequest ...
	EtsiTs102941MessagesCa::EtsiTs102941Data atData = EtsiTs102941MessagesCa::EtsiTs102941Data(EtsiTs102941Data_Version, atDataContent);
	dump_ttcn_object(atData, "EtsiTs102941Data: ");

	EtsiTs103097Module::EtsiTs103097Data__Signed__My signedData;
	if (!AtEnrollmentRequest_POP(idata, atData, signedData))   {
                ERROR_STREAMC << "POP failed" << std::endl;
		return false;
	}
	dump_ttcn_object(signedData, "EtsiTs103097Data__Signed__My: ");

	OCTETSTRING signedData_encoded;
	encEtsiTs103097Data__Signed__My(signedData, signedData_encoded);

	EtsiTs103097Module::EtsiTs103097Data__Encrypted__My dataEncrypted;
	if (!EncryptSignedData_ForAa(idata, signedData_encoded, dataEncrypted))   {
                ERROR_STREAMC << "cannot encrypt Data-Signed for AA " << std::endl;
                return false;
	}
	dump_ttcn_object(dataEncrypted, "EtsiTs102941Data-Encrypted: ");
	if (!encIeee1609Dot2Data(dataEncrypted, ret))   {
                ERROR_STREAMC << "cannot encode encrypted Data-Signed for AA " << std::endl;
                return false;
	}
	dump_ttcn_object(ret, "EtsiTs102941Data-Encrypted (encoded): ");

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::AtEnrollmentRequest_Parse(OCTETSTRING &request_raw, void *ea_prvkey, void *aa_prvkey)
{
	DEBUGC_STREAM_CALLED;

	if (!etsiServices.setDecryptContext(aa_prvkey, NULL))   {
                ERROR_STREAMC << "Cannot set EC enrollment 'Request Parse' context" << std::endl;
                return false;
	}

	OCTETSTRING payload;
	if (!etsiServices.DecryptPayload(request_raw, payload))   {
                ERROR_STREAMC << "decrypt payload failed" << std::endl;
                return false;
	}

	EtsiTs103097Module::EtsiTs103097Data__Signed__My request_data_signed = decEtsiTs103097DataSigned(payload);
	dump_ttcn_object(request_data_signed, "Signed request: ");

	IEEE1609dot2::Ieee1609Dot2Content content;
	if (!IEEE1609dot2_VerifySignedData_C(request_data_signed.content().signedData(), sessionGetItsAtVerificationKey(), content))   {
                ERROR_STREAMC << "Cannot verify Signed Data signature" << std::endl;
                return false;
	}
	else if (!content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_unsecuredData))  {
        	ERROR_STREAMC << "expected data type 'Ieee1609Dot2Content::ALT_unsecuredData'" << std::endl;
		return false;
	}

	EtsiTs102941MessagesCa::EtsiTs102941Data etsi_ts_data = decEtsiTs102941Data(content.unsecuredData());
	dump_ttcn_object(etsi_ts_data, "Etsi TS Data: ");

	if (etsi_ts_data.version() != EtsiTs102941Data_Version)  {
        	ERROR_STREAMC << "unsupported EtsiTs102941Data version: " << etsi_ts_data.version() << std::endl;
		return false;
	}
	else if (!etsi_ts_data.content().ischosen(EtsiTs102941MessagesCa::EtsiTs102941DataContent::ALT_authorizationRequest))   {
        	ERROR_STREAMC << "expected 'authorizationRequest' data type" << std::endl;
		return false;
	}

	EtsiTs102941TypesAuthorization::InnerAtRequest inner_at_request = etsi_ts_data.content().authorizationRequest();
	EtsiTs102941BaseTypes::PublicKeys pubkeys = inner_at_request.publicKeys();
	OCTETSTRING hmac_key = inner_at_request.hmacKey();
	EtsiTs102941TypesAuthorization::SharedAtRequest shared_at_request = inner_at_request.sharedAtRequest();
	EtsiTs102941BaseTypes::EcSignature ec_signature = inner_at_request.ecSignature();
	dump_ttcn_object(ec_signature, "EcSignature: ");

        OCTETSTRING pubkeys_encoded;
        if (!encPublicVerificationKey(pubkeys.verificationKey(), pubkeys_encoded))   {
        	ERROR_STREAMC << "cannot encode public verification key" << std::endl;
		return false;
	}
	if (pubkeys.encryptionKey().is_present())    {
        	OCTETSTRING e_pubkey_encoded;
		if (!encPublicEncryptionKey(pubkeys.encryptionKey(), e_pubkey_encoded))   {
        		ERROR_STREAMC << "cannot encode public encryption key" << std::endl;
			return false;
		}
		pubkeys_encoded += e_pubkey_encoded;
	}

        OCTETSTRING key_tag;
        if (!hmac_sha256(pubkeys_encoded, hmac_key, key_tag))   {
                ERROR_STREAMC << "failed to generate HMAC of PublicKeys data" << std::endl;
                return false;
        }
	dump_ttcn_object(key_tag, "PublicKeys tag: ");
	if (shared_at_request.keyTag() != key_tag)   {
                ERROR_STREAMC << "unexpected value of PublicKey HMAC" << std::endl;
                return false;
	}

	OCTETSTRING ec_signature_payload;
	if (ec_signature.ischosen(EtsiTs102941BaseTypes::EcSignature::ALT_encryptedEcSignature))   {
        	EtsiTs103097Module::EtsiTs103097Data__Encrypted__My ec_signature_encrypted = ec_signature.encryptedEcSignature();

		if (!etsiServices.setRecipient(idata->GetEACertBlob(), ea_prvkey))   {
                	ERROR_STREAMC << "cannot setup EncryptFor context" << std::endl;
			return false;
		}
		else if (!etsiServices.DecryptPayload(ec_signature_encrypted, ec_signature_payload))   {
                	ERROR_STREAMC << "decrypt payload failed" << std::endl;
                	return false;
		}
	}
	else if (ec_signature.ischosen(EtsiTs102941BaseTypes::EcSignature::ALT_ecSignature))   {
        	ERROR_STREAMC << "'ecSignature' type of EcSignature do not supported" << std::endl;
		return false;
	}
	else   {
        	ERROR_STREAMC << "unsupported EcSignature type" << std::endl;
		return false;
	}
	dump_ttcn_object(ec_signature_payload, "Decrypted payload: ");

        EtsiTs103097Module::EtsiTs103097Data__SignedExternalPayload external_payload;
	try  {
        	EtsiTs103097Module::EtsiTs103097Data__SignedExternalPayload_decoder(ec_signature_payload, external_payload, "OER");
	}
	catch (const TC_Error& tc_error) {
        	ERROR_STREAMC << "cannot decode EtsiTs103097Data SignedExternalPayload data" << std::endl;
		return false;
	}
	dump_ttcn_object(external_payload, "Decoded Exrternal Payload: ");

	if (external_payload.protocolVersion() != Ieee1609Dot2Data_ProtocolVersion)   {
        	ERROR_STREAMC << "unexpected ExternalPayload protocol version: " << external_payload.protocolVersion() << std::endl;
		return false;
	}
	else if (!external_payload.content().ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_signedData))   {
        	ERROR_STREAMC << "unexpected Ieee1609Dot2Content data type of external payload: " << external_payload.content().get_selection() << std::endl;
		return false;
	}

	IEEE1609dot2::HashedData ext_data_hash;
	if (!IEEE1609dot2_VerifySignedData_H(external_payload.content().signedData(), sessionGetItsEcVerificationKey(), ext_data_hash))   {
		ERROR_STREAMC << "Cannot verify external payload signed data " << std::endl;
		return false;
	}

	OCTETSTRING sar_encoded, sar_hash;
	if (!encSharedAtRequest(shared_at_request, sar_encoded))   {
		ERROR_STREAMC << "cannot encode EtsiTs102941TypesAuthorization::SharedAtRequest" << std::endl;
		return false;
	}
	else if (!hash_256(sar_encoded, sar_hash))   {
		ERROR_STREAMC << "cannot get hash of sharedAtRequest" << std::endl;
		return false;
	}
	else if (sar_hash != ext_data_hash.sha256HashedData())   {
		ERROR_STREAMC << "unexpected ExternalDataHashvalue" << std::endl;
		return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::AtEnrollmentResponse_Status(OCTETSTRING &response_raw)
{
	DEBUGC_STREAM_CALLED;

	OCTETSTRING payload;
	if (!etsiServices.DecryptPayload(response_raw, payload))   {
        	ERROR_STREAMC << "cannot decrypt payload" << std::endl;
		return false;
	}

	EtsiTs103097Module::EtsiTs103097Data__Signed__My data_signed = decEtsiTs103097DataSigned(payload);

	IEEE1609dot2::Ieee1609Dot2Content content;
	if (!IEEE1609dot2_VerifySignedData_C(data_signed.content().signedData(), NULL, content))   {
                ERROR_STREAMC << "Cannot verify Signed Data signature" << std::endl;
                return false;
	}
	else if (!content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_unsecuredData))  {
        	ERROR_STREAMC << "expected data type 'Ieee1609Dot2Content::ALT_unsecuredData'" << std::endl;
		return false;
	}
	dump_ttcn_object(content, "Signed data content: ");

	EtsiTs102941MessagesCa::EtsiTs102941Data inner_data = decEtsiTs102941Data(content.unsecuredData());
	dump_ttcn_object(inner_data, "Response Inner Data: ");

	if (!inner_data.content().ischosen(EtsiTs102941MessagesCa::EtsiTs102941DataContent::ALT_authorizationResponse))   {
        	ERROR_STREAMC << "expected 'AuthorizationResponse' inner data type " << std::endl;
		return false;
	}

	EtsiTs102941TypesAuthorization::AuthorizationResponseCode respCode = inner_data.content().authorizationResponse().responseCode();
	if (respCode != EtsiTs102941TypesAuthorization::AuthorizationResponseCode::ok)   {
        	ERROR_STREAMC << "expected response code 'OK', received '" << respCode.enum_to_str(respCode) << "'" << std::endl;
		return false;
	}

	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

bool
ItsPkiSession::AtEnrollmentResponse_Parse(OCTETSTRING &response_raw, OCTETSTRING &ret_cert)
{
	DEBUGC_STREAM_CALLED;

	dump_ttcn_object(response_raw, "AtEnrollment Response: ");
	OCTETSTRING payload;
	if (!etsiServices.DecryptPayload(response_raw, payload))   {
                ERROR_STREAMC << "decrypt payload failed" << std::endl;
                return false;
	}

	EtsiTs103097Module::EtsiTs103097Data__Signed__My data_signed = decEtsiTs103097DataSigned(payload);
	dump_ttcn_object(data_signed, "Response EtsiTs103097DataSigned__My: ");

	IEEE1609dot2::Ieee1609Dot2Content content;
	if (!IEEE1609dot2_VerifySignedData_C(data_signed.content().signedData(), NULL, content))   {
                ERROR_STREAMC << "Cannot verify Signed Data signature" << std::endl;
                return false;
	}
	else if (!content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_unsecuredData))  {
        	ERROR_STREAMC << "expected data type 'Ieee1609Dot2Content::ALT_unsecuredData'" << std::endl;
		return false;
	}
	dump_ttcn_object(content, "Signed data content: ");

	EtsiTs102941MessagesCa::EtsiTs102941Data inner_data = decEtsiTs102941Data(content.unsecuredData());
	dump_ttcn_object(inner_data, "Response Inner Data: ");

	if (!inner_data.content().ischosen(EtsiTs102941MessagesCa::EtsiTs102941DataContent::ALT_authorizationResponse))  {
        	ERROR_STREAMC << "invalid response inner data type: '" << inner_data.content().get_selection() << "'" << std::endl;
		return false;
	}

	EtsiTs102941TypesAuthorization::InnerAtResponse inner_at_response = inner_data.content().authorizationResponse();
	dump_ttcn_object(inner_at_response, "EtsiTs102941TypesAuthorization::InnerAtResponse : ");
	if (inner_at_response.responseCode() != EtsiTs102941TypesAuthorization::AuthorizationResponseCode::ok)   {
        	ERROR_STREAMC << "enrollment failed with response status '" << inner_at_response.responseCode() << "'" << std::endl;
		return false;
	}

	EtsiTs103097Module::EtsiTs103097Certificate cert = inner_at_response.certificate();
	dump_ttcn_object(cert, "ITS AT Certificate: ");

	if (!encEtsiTs103097Certificate(cert, sessionItsAtCert))    {
        	ERROR_STREAMC << "cannot encode AT EtsiTs103097Certificate" << std::endl;
		return false;
	}
	dump_ttcn_object(sessionItsAtCert, "ITS AT Certificate (encoded): ");

	ret_cert = sessionItsAtCert;
	DEBUGC_STREAM_RETURNS_OK;
	return true;
}

max_stars_repo_name: IDnomic/itspkilib

max_issues_repo_name: IDnomic/itspkilib

max_forks_repo_name: IDnomic/itspkilib


text:
/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You 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.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee++ --- ParserSuite adaptors
 *
 * This file provides code for adapting ParserSuite results to IronBee++.
 *
 * @author Christopher Alfeld <calfeld@qualys.com>
 */

#ifndef __IBPP__PARSERSUITE_ADAPTORS__
#define __IBPP__PARSERSUITE_ADAPTORS__

#include <ironbee/module/parser_suite.hpp>

#include <ironbeepp/parsed_header.hpp>

#include <boost/iterator/transform_iterator.hpp>

namespace IronBee {

/**
 * Functional to translate a ParserSuite header to a ParsedHeader.
 *
 * Headers with multiple values (extended headers) will have their values
 * concatenated.  Headers with a single value will have their header directly
 * aliased.
 **/
class PSHeaderToParsedHeader :
    public std::unary_function<
        const ParserSuite::parse_headers_result_t::header_t&,
        ParsedHeader
    >
{
public:
    /**
     * Constructor.
     *
     * @param[in] memory_manager Memory pool to use for allocations.
     **/
    explicit
    PSHeaderToParsedHeader(MemoryManager memory_manager);

    /**
     * Call operator.
     *
     * @param[in] header Header to translate.
     * @return ParsedHeader aliasing members of @a header.
     **/
    ParsedHeader operator()(
        const ParserSuite::parse_headers_result_t::header_t& header
    ) const;

private:
    //! Memory manager to allocate bytestrings and ParserHeader from.
    MemoryManager m_memory_manager;
};

//! Type of iterator from adapt_headers().
typedef boost::transform_iterator<
    PSHeaderToParsedHeader,
    ParserSuite::parse_headers_result_t::headers_t::const_iterator
> psheader_to_parsed_header_const_iterator;

//! Range of @ref psheader_to_parsed_header_const_iterator.
typedef boost::iterator_range<
    psheader_to_parsed_header_const_iterator
> psheader_to_parsed_header_const_range_t;

/**
 * Adapt ParserSuite::parse_headers_result_t::headers_t to a sequence of
 * ParsedHeader.
 *
 * @param[in] memory_manager Memory manager to use.
 * @param[in] headers        Headers to adapt.
 * @return Range of ParsedHeader.
 **/
psheader_to_parsed_header_const_range_t psheaders_to_parsed_headers(
    IronBee::MemoryManager                                memory_manager,
    const ParserSuite::parse_headers_result_t::headers_t& headers
);

} // IronBee

#endif

max_stars_repo_name: crustymonkey/ironbee

max_issues_repo_name: crustymonkey/ironbee

max_forks_repo_name: crustymonkey/ironbee


text:
#include "generator/check_model.hpp"
#include "generator/data_version.hpp"
#include "generator/dumper.hpp"
#include "generator/feature_generator.hpp"
#include "generator/generate_info.hpp"
#include "generator/geo_objects/geo_objects_generator.hpp"
#include "generator/locality_sorter.hpp"
#include "generator/osm_source.hpp"
#include "generator/processor_factory.hpp"
#include "generator/raw_generator.hpp"
#include "generator/regions/collector_region_info.hpp"
#include "generator/regions/regions.hpp"
#include "generator/statistics.hpp"
#include "generator/streets/streets.hpp"
#include "generator/translator_collection.hpp"
#include "generator/translator_factory.hpp"
#include "generator/unpack_mwm.hpp"

#include "geocoder/geocoder.hpp"

#include "indexer/classificator_loader.hpp"
#include "indexer/features_vector.hpp"
#include "indexer/locality_index_builder.hpp"
#include "indexer/map_style_reader.hpp"

#include "platform/platform.hpp"

#include "coding/endianness.hpp"

#include "base/file_name_utils.hpp"
#include "base/timer.hpp"

#include <boost/program_options.hpp>

#include <csignal>
#include <cstdlib>
#include <fstream>
#include <string>

#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
#include <boost/stacktrace.hpp>

#include "build_version.hpp"
#include "defines.hpp"

using namespace std;

namespace
{
char const * GetDataPathHelp()
{
  static string const kHelp =
      "Directory where the generated mwms are put into. Also used as the path for helper "
      "functions, such as those that calculate statistics and regenerate sections. "
      "Default: " +
      Platform::GetCurrentWorkingDirectory() + "/../../data'.";
  return kHelp.c_str();
}
}  // namespace

struct CliCommandOptions
{
  std::string m_intermediate_data_path;
  std::string m_osm_file_type;
  std::string m_osm_file_name;
  std::string m_node_storage;
  std::string m_user_resource_path;
  std::string m_output;
  std::string m_data_path;
  std::string m_nodes_list_path;
  std::string m_regions_features;
  std::string m_allow_addressless_for_countries;
  std::string m_ids_without_addresses;
  std::string m_geo_objects_key_value;
  std::string m_regions_index;
  std::string m_regions_key_value;
  std::string m_streets_key_value;
  std::string m_streets_features;
  std::string m_geo_objects_features;
  std::string m_key_value;
  bool m_preprocess = false;
  bool m_generate_region_features = false;
  bool m_generate_features = false;
  bool m_generate_regions = false;
  bool m_generate_geo_objects_index = false;
  bool m_generate_regions_kv = false;
  bool m_generate_streets_features = false;
  bool m_generate_geo_objects_features = false;
  bool m_generate_geocoder_token_index = false;
  bool m_verbose = false;
};

namespace po = boost::program_options;

CliCommandOptions DefineOptions(int argc, char * argv[])
{
  CliCommandOptions o;
  po::options_description optionsDescription;

  optionsDescription.add_options()
     ("osm_file_name",
         po::value(&o.m_osm_file_name)->default_value(""),
         "Input osm area file.")
     ("osm_file_type",
         po::value(&o.m_osm_file_type)->default_value("xml"),
         "Input osm area file type [xml, o5m].")
     ("data_path",
         po::value(&o.m_data_path)->default_value(""),
         GetDataPathHelp())
     ("user_resource_path",
         po::value(&o.m_user_resource_path)->default_value(""),
         "User defined resource path for classificator.txt and etc.")
     ("intermediate_data_path",
         po::value(&o.m_intermediate_data_path)->default_value(""),
         "Path to stored nodes, ways, relations.")
     ("output",
         po::value(&o.m_output)->default_value(""),
         "File name for process (without 'mwm' ext).")
     ("node_storage",
         po::value(&o.m_node_storage)->default_value("map"),
         "Type of storage for intermediate points representation. Available: raw, map, mem.")
     ("preprocess",
         po::value(&o.m_preprocess)->default_value(false),
         "1st pass - create nodes/ways/relations data.")
     ("generate_features",
         po::value(&o.m_generate_features)->default_value(false),
         "2nd pass - generate intermediate features.")
     ("generate_region_features",
         po::value(&o.m_generate_region_features)->default_value(false),
         "Generate intermediate features for regions to use in regions index and borders generation.")
     ("generate_streets_features",
         po::value(&o.m_generate_streets_features)->default_value(false),
         "Generate intermediate features for streets to use in server-side forward geocoder.")
     ("generate_geo_objects_features",
         po::value(&o.m_generate_geo_objects_features)->default_value(false),
         "Generate intermediate features for geo objects to use in geo objects index.")
     ("generate_geo_objects_index",
         po::value(&o.m_generate_geo_objects_index)->default_value(false),
         "Generate objects and index for server-side reverse geocoder.")
     ("generate_regions",
         po::value(&o.m_generate_regions)->default_value(false),
         "Generate regions index and borders for server-side reverse geocoder.")
     ("generate_regions_kv",
         po::value(&o.m_generate_regions_kv)->default_value(false),
         "Generate regions key-value for server-side reverse geocoder.")
     ("nodes_list_path",
         po::value(&o.m_nodes_list_path)->default_value(""),
         "Path to file containing list of node ids we need to add to locality index. May be empty.")
     ("regions_index",
         po::value(&o.m_regions_index)->default_value(""),
         "Input regions index file.")
     ("regions_key_value",
         po::value(&o.m_regions_key_value)->default_value(""),
         "Input regions key-value file.")
     ("streets_features",
         po::value(&o.m_streets_features)->default_value(""),
         "Input tmp.mwm file with streets.")
     ("streets_key_value",
         po::value(&o.m_streets_key_value)->default_value(""),
         "Output streets key-value file.")
     ("geo_objects_features",
         po::value(&o.m_geo_objects_features)->default_value(""),
         "Input tmp.mwm file with geo objects.")
     ("ids_without_addresses",
         po::value(&o.m_ids_without_addresses)->default_value(""),
         "Output file with objects ids without addresses.")
     ("geo_objects_key_value",
         po::value(&o.m_geo_objects_key_value)->default_value(""),
         "Output geo objects key-value file.")
     ("allow_addressless_for_countries",
         po::value(&o.m_allow_addressless_for_countries)->default_value("*"),
         "Allow addressless buildings for only specified countries separated by commas.")
     ("regions_features",
         po::value(&o.m_regions_features)->default_value(""),
         "Input tmp.mwm file with regions.")
     ("generate_geocoder_token_index",
         po::value(&o.m_generate_geocoder_token_index)->default_value(false),
         "Generate geocoder token index.")
     ("key_value",
         po::value(&o.m_key_value)->default_value(""),
         "Input key-value file (.jsonl or .jsonl.gz).")
     ("verbose",
         po::value(&o.m_verbose)->default_value(false),
         "Provide more detailed output.")
     ("version", "get version")
     ("help", "produce help message");

  po::variables_map vm;

  po::store(po::parse_command_line(argc, argv, optionsDescription), vm);
  po::notify(vm);

  if (vm.count("help"))
  {
    std::cout << optionsDescription << std::endl;
    exit(0);
  }

  if (vm.count("version"))
  {
    std::cout << generator::DataVersion::GetCodeVersion() << std::endl;
    exit(0);
  }

  return o;
}

using namespace generator;

int GeneratorToolMain(int argc, char ** argv)
{
  CHECK(IsLittleEndian(), ("Only little-endian architectures are supported."));

  CliCommandOptions options;

  options = DefineOptions(argc, argv);

  Platform & pl = GetPlatform();
  auto threadsCount = pl.CpuCores();

  if (!options.m_user_resource_path.empty())
  {
    pl.SetResourceDir(options.m_user_resource_path);
    pl.SetSettingsDir(options.m_user_resource_path);
  }

  string const path =
      options.m_data_path.empty() ? pl.WritableDir() : base::AddSlashIfNeeded(options.m_data_path);

  // So that stray GetWritablePathForFile calls do not crash the generator.
  pl.SetWritableDirForTests(path);

  feature::GenerateInfo genInfo;
  genInfo.m_verbose = options.m_verbose;
  genInfo.m_intermediateDir = options.m_intermediate_data_path.empty()
                                  ? path
                                  : base::AddSlashIfNeeded(options.m_intermediate_data_path);
  genInfo.m_targetDir = genInfo.m_tmpDir = path;

  /// @todo Probably, it's better to add separate option for .mwm.tmp files.
  if (!options.m_intermediate_data_path.empty())
  {
    string const tmpPath = base::JoinPath(genInfo.m_intermediateDir, "tmp");
    if (Platform::MkDir(tmpPath) != Platform::ERR_UNKNOWN)
      genInfo.m_tmpDir = tmpPath;
  }
  if (!options.m_node_storage.empty())
    genInfo.SetNodeStorageType(options.m_node_storage);
  if (!options.m_osm_file_type.empty())
    genInfo.SetOsmFileType(options.m_osm_file_type);

  genInfo.m_osmFileName = options.m_osm_file_name;
  genInfo.m_fileName = options.m_output;

  // Use merged style.
  GetStyleReader().SetCurrentStyle(MapStyleMerged);

  classificator::Load();

  // Generate intermediate files.
  if (options.m_preprocess)
  {
    DataVersion{options.m_osm_file_name}.DumpToPath(genInfo.m_intermediateDir);

    LOG(LINFO, ("Generating intermediate data ...."));
    if (!GenerateIntermediateData(genInfo))
      return EXIT_FAILURE;
  }

  // Generate .mwm.tmp files.
  if (options.m_generate_features || options.m_generate_region_features ||
      options.m_generate_streets_features || options.m_generate_geo_objects_features)
  {
    RawGenerator rawGenerator(genInfo, threadsCount);
    if (options.m_generate_region_features)
      rawGenerator.GenerateRegionFeatures(options.m_output);
    if (options.m_generate_streets_features)
      rawGenerator.GenerateStreetsFeatures(options.m_output);
    if (options.m_generate_geo_objects_features)
      rawGenerator.GenerateGeoObjectsFeatures(options.m_output);

    if (!rawGenerator.Execute())
      return EXIT_FAILURE;

    genInfo.m_bucketNames = rawGenerator.GetNames();
  }

  if (genInfo.m_bucketNames.empty() && !options.m_output.empty())
    genInfo.m_bucketNames.push_back(options.m_output);

  if (!options.m_streets_key_value.empty())
  {
    streets::GenerateStreets(options.m_regions_index, options.m_regions_key_value,
                             options.m_streets_features, options.m_geo_objects_features,
                             options.m_streets_key_value, options.m_verbose, threadsCount);
  }

  if (!options.m_geo_objects_key_value.empty())
  {
    if (!geo_objects::GenerateGeoObjects(
            options.m_regions_index, options.m_regions_key_value, options.m_geo_objects_features,
            options.m_ids_without_addresses, options.m_geo_objects_key_value, options.m_verbose,
            threadsCount))
      return EXIT_FAILURE;
  }

  if (options.m_generate_geo_objects_index || options.m_generate_regions)
  {
    if (options.m_output.empty())
    {
      LOG(LCRITICAL, ("Bad output or intermediate_data_path. Output:", options.m_output));
      return EXIT_FAILURE;
    }

    auto const locDataFile = base::JoinPath(path, options.m_output + LOC_DATA_FILE_EXTENSION);
    auto const outFile = base::JoinPath(path, options.m_output + LOC_IDX_FILE_EXTENSION);
    if (options.m_generate_geo_objects_index)
    {
      if (!feature::GenerateGeoObjectsData(options.m_geo_objects_features,
                                           options.m_nodes_list_path, locDataFile))
      {
        LOG(LCRITICAL, ("Error generating geo objects data."));
        return EXIT_FAILURE;
      }

      LOG(LINFO, ("Saving geo objects index to", outFile));
      if (!indexer::BuildGeoObjectsIndexFromDataFile(
              locDataFile, outFile, DataVersion::LoadFromPath(path).GetVersionJson(),
              DataVersion::kFileTag))
      {
        LOG(LCRITICAL, ("Error generating geo objects index."));
        return EXIT_FAILURE;
      }
    }

    if (options.m_generate_regions)
    {
      if (!feature::GenerateRegionsData(options.m_regions_features, locDataFile))
      {
        LOG(LCRITICAL, ("Error generating regions data."));
        return EXIT_FAILURE;
      }

      LOG(LINFO, ("Saving regions index to", outFile));

      if (!indexer::BuildRegionsIndexFromDataFile(locDataFile, outFile,
                                                  DataVersion::LoadFromPath(path).GetVersionJson(),
                                                  DataVersion::kFileTag))
      {
        LOG(LCRITICAL, ("Error generating regions index."));
        return EXIT_FAILURE;
      }
      if (!feature::GenerateBorders(options.m_regions_features, outFile))
      {
        LOG(LCRITICAL, ("Error generating regions borders."));
        return EXIT_FAILURE;
      }
    }
  }

  if (options.m_generate_regions_kv)
  {
    auto const pathInRegionsCollector =
        genInfo.GetTmpFileName(genInfo.m_fileName, regions::CollectorRegionInfo::kDefaultExt);
    auto const pathInRegionsTmpMwm = genInfo.GetTmpFileName(genInfo.m_fileName);
    auto const pathOutRepackedRegionsTmpMwm =
        genInfo.GetTmpFileName(genInfo.m_fileName + "_repacked");
    auto const pathOutRegionsKv = genInfo.GetIntermediateFileName(genInfo.m_fileName, ".jsonl");
    regions::GenerateRegions(pathInRegionsTmpMwm, pathInRegionsCollector, pathOutRegionsKv,
                             pathOutRepackedRegionsTmpMwm, options.m_verbose, threadsCount);
  }

  if (options.m_generate_geocoder_token_index)
  {
    if (options.m_key_value.empty())
    {
      LOG(LCRITICAL, ("Unspecified key-value file."));
      return EXIT_FAILURE;
    }

    geocoder::Geocoder geocoder;
    geocoder.LoadFromJsonl(options.m_key_value, threadsCount);

    auto const tokenIndexFile = base::JoinPath(path, options.m_output);
    geocoder.SaveToBinaryIndex(tokenIndexFile);
  }

  return 0;
}

void ErrorHandler(int signum)
{
  // Avoid recursive calls.
  signal(signum, SIG_DFL);

  // If there was an exception, then we will print the message.
  try
  {
    if (auto const eptr = current_exception())
      rethrow_exception(eptr);
  }
  catch (RootException const & e)
  {
    cerr << "Core exception: " << e.Msg() << "\n";
  }
  catch (exception const & e)
  {
    cerr << "Std exception: " << e.what() << "\n";
  }
  catch (...)
  {
    cerr << "Unknown exception.\n";
  }

  // Print stack stack.
  cerr << boost::stacktrace::stacktrace();
  // We raise the signal SIGABRT, so that there would be an opportunity to make a core dump.
  raise(SIGABRT);
}

int main(int argc, char ** argv)
{
  signal(SIGABRT, ErrorHandler);
  signal(SIGSEGV, ErrorHandler);
  try
  {
    return GeneratorToolMain(argc, argv);
  }
  catch (po::error & e)
  {
    std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
    return 1;
  }
  catch (std::exception & e)
  {
    std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
    return 1;
  }
}

max_stars_repo_name: LaGrunge/geocore

max_issues_repo_name: LaGrunge/geocore

max_forks_repo_name: LaGrunge/geocore