<commit_before>#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <list>
#include <map>
#include <algorithm>
#include <locale>
#include <getopt.h>
#include <stdlib.h>
#include <unordered_map>

#include "search.h"
#include "stats.h"
#include "seq.h"

void build_patterns(std::ifstream & kmers_f, std::vector <std::pair <std::string, Node::Type> > & patterns)
{
    std::string tmp;
    while (!kmers_f.eof()) {
        std::getline(kmers_f, tmp);
        std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper);
        if (!tmp.empty()) {
            size_t tab = tmp.find('\t');
            if (tab == std::string::npos) {
                patterns.push_back(std::make_pair(tmp, Node::Type::adapter));
            } else {
                patterns.push_back(std::make_pair(tmp.substr(0, tab), Node::Type::adapter));
            }
        }
    }
    kmers_f.close();
}

ReadType check_read(std::string const & read, Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns, int errors)
{
    if (errors) {
        return (ReadType)search_inexact(read, root, patterns, errors);
    } else {
        return (ReadType)search_any(read, root);
    }
}

void filter_single_reads(std::ifstream & reads_f, std::ofstream & bad_f,
                         Stats & stats, Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns, int errors)
{
    Seq read;
    int processed = 0;

    while (read.read_seq(reads_f)) {
        ReadType type = check_read(read.seq, root, patterns, errors);
        stats.update(type);
        if (type != ReadType::ok) {
            read.write_seq(bad_f);
        }

        processed += 1;
        if (processed % 1000000 == 0) {
            std::cout << "Processed: " << processed << std::endl;
        }
    }
}

void filter_paired_reads(std::ifstream & reads1_f, std::ifstream & reads2_f,
                         std::ofstream & bad1_f, std::ofstream & bad2_f,
                         std::ofstream & se1_f, std::ofstream & se2_f,
                         Stats & stats1, Stats & stats2,
                         Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns,
                         int errors)
{
    Seq read1;
    Seq read2;
    int processed = 0;

    while (read1.read_seq(reads1_f) && read2.read_seq(reads2_f)) {
        ReadType type1 = check_read(read1.seq, root, patterns, errors);
        ReadType type2 = check_read(read2.seq, root, patterns, errors);
        if (type1 == ReadType::ok && type2 == ReadType::ok) {

        } else {
            stats1.update(type1, false);
            stats2.update(type2, false);
            if (type1 == ReadType::ok) {
                read1.write_seq(se1_f);
                read2.write_seq(bad2_f);
            } else if (type2 == ReadType::ok) {
                read1.write_seq(bad1_f);
                read2.write_seq(se2_f);
            } else {
                read1.write_seq(bad1_f);
                read2.write_seq(bad2_f);
            }
        }

        processed += 1;
        if (processed % 1000000 == 0) {
            std::cout << "Processed: " << processed << std::endl;
        }
    }
}

std::string basename(std::string const & path)
{
    std::string res(path);
    size_t pos = res.find_last_of('/');
    if (pos != std::string::npos) {
        res.erase(0, pos);
    }
    pos = res.find('.');
    if (pos != std::string::npos) {
        res.erase(pos, path.size());
    }
    return res;
}

void print_help()
{
    std::cout << "./extractor [-i raw_data.fastq | -1 raw_data1.fastq -2 raw_data2.fastq] -o output_dir --fragments fragments.dat -e errors" << std::endl;
}

int main(int argc, char ** argv)
{
    Node root('0');
    std::vector <std::pair<std::string, Node::Type> > patterns;

    std::string kmers, reads, out_dir;
    std::string reads1, reads2;
    char rez = 0;
    int errors = 0;
    const struct option long_options[] = {
        {"fragments",required_argument,NULL,'a'},
        {NULL,0,NULL,0}
    };

    while ((rez = getopt_long(argc, argv, "1:2:l:p:a:i:o:e:", long_options, NULL)) != -1) {
        switch (rez) {
        case 'a':
            kmers = optarg;
            break;
        case 'i':
            reads = optarg;
            break;
        case '1':
            reads1 = optarg;
            break;
        case '2':
            reads2 = optarg;
            break;
        case 'o':
            out_dir = optarg;
            break;
        case 'e':
            errors = std::atoi(optarg);
            break;
        case '?':
            print_help();
            return -1;
        }
    }

    if (errors < 0 || errors > 2) {
        std::cout << "possible errors count are 0, 1, 2" << std::endl;
        return -1;
    }

    if (kmers.empty() || out_dir.empty() || (
            reads.empty() &&
            (reads1.empty() || reads2.empty()))) {
        print_help();
        return -1;
    }

    std::ifstream kmers_f (kmers.c_str());
    if (!kmers_f.good()) {
        std::cout << "Cannot open kmers file" << std::endl;
        print_help();
        return -1;
    }

    std::cout << "Building patterns..." << std::endl;
    build_patterns(kmers_f, patterns);

    if (patterns.empty()) {
        std::cout << "patterns are empty" << std::endl;
        return -1;
    }

    std::cout << "Building trie..." << std::endl;
    build_trie(root, patterns, errors);
	add_failures(root);

    std::cout << "Iterate reads..." << std::endl;
    if (!reads.empty()) {
        std::string reads_base = basename(reads);
        std::ifstream reads_f (reads.c_str());
        std::ofstream bad_f((out_dir + "/" + reads_base + ".filtered.fastq").c_str(), std::ofstream::out);

        if (!reads_f.good()) {
            std::cout << "Cannot open reads file" << std::endl;
            print_help();
            return -1;
        }

        if (!bad_f.good()) {
            std::cout << "Cannot open output file" << std::endl;
            print_help();
            return -1;
        }

        Stats stats(reads);

        filter_single_reads(reads_f, bad_f, stats, &root, patterns, errors);

        std::cout << stats;

        bad_f.close();
        reads_f.close();
    } else {
        std::string reads1_base = basename(reads1);
        std::string reads2_base = basename(reads2);
        std::ifstream reads1_f(reads1.c_str());
        std::ifstream reads2_f(reads2.c_str());
        std::ofstream se1_f((out_dir + "/" + reads1_base + ".se.fastq").c_str(),
                            std::ofstream::out);
        std::ofstream se2_f((out_dir + "/" + reads2_base + ".se.fastq").c_str(),
                            std::ofstream::out);
        std::ofstream bad1_f((out_dir + "/" + reads1_base + ".filtered.fastq").c_str(),
                            std::ofstream::out);
        std::ofstream bad2_f((out_dir + "/" + reads2_base + ".filtered.fastq").c_str(),
                            std::ofstream::out);

        if (!reads1_f.good() || !reads2_f.good()) {
            std::cout << "reads file is bad" << std::endl;
            print_help();
            return -1;
        }

        if (!bad1_f.good() || !bad2_f.good() ||
                !se1_f.good() || !se2_f.good()) {
            std::cout << "out file is bad" << std::endl;
            print_help();
            return -1;
        }

        Stats stats1(reads1);
        Stats stats2(reads2);

        filter_paired_reads(reads1_f, reads2_f,
                            bad1_f, bad2_f, se1_f, se2_f,
                            stats1, stats2,
                            &root, patterns, errors);

        std::cout << stats1;
        std::cout << stats2;

        bad1_f.close();
        bad2_f.close();
        reads1_f.close();
        reads2_f.close();
    }
}
<commit_msg>messages<commit_after>#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <list>
#include <map>
#include <algorithm>
#include <locale>
#include <getopt.h>
#include <stdlib.h>
#include <unordered_map>

#include "search.h"
#include "stats.h"
#include "seq.h"

void build_patterns(std::ifstream & kmers_f, std::vector <std::pair <std::string, Node::Type> > & patterns)
{
    std::string tmp;
    while (!kmers_f.eof()) {
        std::getline(kmers_f, tmp);
        std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper);
        if (!tmp.empty()) {
            size_t tab = tmp.find('\t');
            if (tab == std::string::npos) {
                patterns.push_back(std::make_pair(tmp, Node::Type::adapter));
            } else {
                patterns.push_back(std::make_pair(tmp.substr(0, tab), Node::Type::adapter));
            }
        }
    }
    kmers_f.close();
}

ReadType check_read(std::string const & read, Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns, int errors)
{
    if (errors) {
        return (ReadType)search_inexact(read, root, patterns, errors);
    } else {
        return (ReadType)search_any(read, root);
    }
}

void filter_single_reads(std::ifstream & reads_f, std::ofstream & bad_f,
                         Stats & stats, Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns, int errors)
{
    Seq read;
    int processed = 0;

    while (read.read_seq(reads_f)) {
        ReadType type = check_read(read.seq, root, patterns, errors);
        stats.update(type);
        if (type != ReadType::ok) {
            read.write_seq(bad_f);
        }

        processed += 1;
        if (processed % 1000000 == 0) {
            std::cout << "Processed: " << processed << std::endl;
        }
    }
}

void filter_paired_reads(std::ifstream & reads1_f, std::ifstream & reads2_f,
                         std::ofstream & bad1_f, std::ofstream & bad2_f,
                         std::ofstream & se1_f, std::ofstream & se2_f,
                         Stats & stats1, Stats & stats2,
                         Node * root, std::vector <std::pair<std::string, Node::Type> > const & patterns,
                         int errors)
{
    Seq read1;
    Seq read2;
    int processed = 0;

    while (read1.read_seq(reads1_f) && read2.read_seq(reads2_f)) {
        ReadType type1 = check_read(read1.seq, root, patterns, errors);
        ReadType type2 = check_read(read2.seq, root, patterns, errors);
        if (type1 == ReadType::ok && type2 == ReadType::ok) {

        } else {
            stats1.update(type1, false);
            stats2.update(type2, false);
            if (type1 == ReadType::ok) {
                read1.write_seq(se1_f);
                read2.write_seq(bad2_f);
            } else if (type2 == ReadType::ok) {
                read1.write_seq(bad1_f);
                read2.write_seq(se2_f);
            } else {
                read1.write_seq(bad1_f);
                read2.write_seq(bad2_f);
            }
        }

        processed += 1;
        if (processed % 1000000 == 0) {
            std::cout << "Processed: " << processed << std::endl;
        }
    }
}

std::string basename(std::string const & path)
{
    std::string res(path);
    size_t pos = res.find_last_of('/');
    if (pos != std::string::npos) {
        res.erase(0, pos);
    }
    pos = res.find('.');
    if (pos != std::string::npos) {
        res.erase(pos, path.size());
    }
    return res;
}

void print_help()
{
    std::cout << "./extractor [-i raw_data.fastq | -1 raw_data1.fastq -2 raw_data2.fastq] -o output_dir --fragments fragments.dat -e errors" << std::endl;
}

int main(int argc, char ** argv)
{
    Node root('0');
    std::vector <std::pair<std::string, Node::Type> > patterns;

    std::string kmers, reads, out_dir;
    std::string reads1, reads2;
    char rez = 0;
    int errors = 0;
    const struct option long_options[] = {
        {"fragments",required_argument,NULL,'a'},
        {NULL,0,NULL,0}
    };

    while ((rez = getopt_long(argc, argv, "1:2:l:p:a:i:o:e:", long_options, NULL)) != -1) {
        switch (rez) {
        case 'a':
            kmers = optarg;
            break;
        case 'i':
            reads = optarg;
            break;
        case '1':
            reads1 = optarg;
            break;
        case '2':
            reads2 = optarg;
            break;
        case 'o':
            out_dir = optarg;
            break;
        case 'e':
            errors = std::atoi(optarg);
            break;
        case '?':
            print_help();
            return -1;
        }
    }

    if (errors < 0 || errors > 2) {
        std::cout << "possible errors count are 0, 1, 2" << std::endl;
        return -1;
    }

    if (kmers.empty() || out_dir.empty() || (
            reads.empty() &&
            (reads1.empty() || reads2.empty()))) {
        print_help();
        return -1;
    }

    std::ifstream kmers_f (kmers.c_str());
    if (!kmers_f.good()) {
        std::cout << "Cannot open kmers file" << std::endl;
        print_help();
        return -1;
    }

    std::cout << "Building patterns..." << std::endl;
    build_patterns(kmers_f, patterns);

    if (patterns.empty()) {
        std::cout << "patterns are empty" << std::endl;
        return -1;
    }

    std::cout << "Building trie..." << std::endl;
    build_trie(root, patterns, errors);
	add_failures(root);

    std::cout << "Iterate reads..." << std::endl;
    if (!reads.empty()) {
        std::string reads_base = basename(reads);
        std::ifstream reads_f (reads.c_str());
        std::ofstream bad_f((out_dir + "/" + reads_base + ".filtered.fastq").c_str(), std::ofstream::out);

        if (!reads_f.good()) {
            std::cout << "Cannot open reads file" << std::endl;
            print_help();
            return -1;
        }

        if (!bad_f.good()) {
            std::cout << "Cannot open output file" << std::endl;
            print_help();
            return -1;
        }

        Stats stats(reads);

        filter_single_reads(reads_f, bad_f, stats, &root, patterns, errors);

        std::cout << stats;

        bad_f.close();
        reads_f.close();
    } else {
        std::string reads1_base = basename(reads1);
        std::string reads2_base = basename(reads2);
        std::ifstream reads1_f(reads1.c_str());
        std::ifstream reads2_f(reads2.c_str());

        std::string file_name_se1 = out_dir + "/" + reads1_base + ".se.fastq";
        std::string file_name_se2 = out_dir + "/" + reads2_base + ".se.fastq";
        std::string file_name_bad1 = out_dir + "/" + reads1_base + ".filtered.fastq";
        std::string file_name_bad2 = out_dir + "/" + reads2_base + ".filtered.fastq";

        std::ofstream se1_f(file_name_se1.c_str(),
                            std::ofstream::out);
        std::ofstream se2_f(file_name_se2.c_str(),
                            std::ofstream::out);
        std::ofstream bad1_f(file_name_bad1.c_str(),
                            std::ofstream::out);
        std::ofstream bad2_f(file_name_bad2.c_str(),
                            std::ofstream::out);

        std::cout << "Created output files:" << std::endl;
        std::cout << "\t" << file_name_se1 << std::endl;
        std::cout << "\t" << file_name_se2 << std::endl;
        std::cout << "\t" << file_name_bad1 << std::endl;
        std::cout << "\t" << file_name_bad2 << std::endl;

        if (!reads1_f.good() || !reads2_f.good()) {
            std::cout << "reads file is bad" << std::endl;
            print_help();
            return -1;
        }

        if (!bad1_f.good() || !bad2_f.good() ||
                !se1_f.good() || !se2_f.good()) {
            std::cout << "out file is bad" << std::endl;
            print_help();
            return -1;
        }

        Stats stats1(reads1);
        Stats stats2(reads2);

        filter_paired_reads(reads1_f, reads2_f,
                            bad1_f, bad2_f, se1_f, se2_f,
                            stats1, stats2,
                            &root, patterns, errors);

        std::cout << stats1;
        std::cout << stats2;

        bad1_f.close();
        bad2_f.close();
        reads1_f.close();
        reads2_f.close();
    }
}
<|endoftext|>


<commit_before>/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed in accordance with the terms specified in
 *  the LICENSE file found in the root directory of this source tree.
 */

#include <map>
#include <string>

#include <osquery/config/config.h>
#include <osquery/logger.h>
#include <osquery/registry_factory.h>
#include <osquery/tables/yara/yara_utils.h>

/// The file change event publishers are slightly different in OS X and Linux.
#ifdef __APPLE__
#include <osquery/events/darwin/fsevents.h>
#elif __linux__
#include <osquery/events/linux/inotify.h>
#endif

#ifdef CONCAT
#undef CONCAT
#endif
#include <yara.h>

namespace osquery {

/// The file change event publishers are slightly different in OS X and Linux.
#ifdef __APPLE__
using FileEventSubscriber = EventSubscriber<FSEventsEventPublisher>;
using FileEventContextRef = FSEventsEventContextRef;
using FileSubscriptionContextRef = FSEventsSubscriptionContextRef;
#define FILE_CHANGE_MASK                                                       \
  kFSEventStreamEventFlagItemCreated | kFSEventStreamEventFlagItemModified |   \
      kFSEventStreamEventFlagItemRenamed
#elif __linux__
using FileEventSubscriber = EventSubscriber<INotifyEventPublisher>;
using FileEventContextRef = INotifyEventContextRef;
using FileSubscriptionContextRef = INotifySubscriptionContextRef;
#define FILE_CHANGE_MASK                                                       \
  ((IN_CREATE) | (IN_CLOSE_WRITE) | (IN_MODIFY) | (IN_MOVED_TO))
#endif

/**
 * @brief Track YARA matches to files.
 */
class YARAEventSubscriber : public FileEventSubscriber {
 public:
  Status init() override {
    return Status(0);
  }

  void configure() override;

 private:
  /**
   * @brief This exports a single Callback for FSEventsEventPublisher events.
   *
   * @param ec The Callback type receives an EventContextRef substruct
   * for the FSEventsEventPublisher declared in this EventSubscriber subclass.
   *
   * @return Status
   */
  Status Callback(const FileEventContextRef& ec,
                  const FileSubscriptionContextRef& sc);
};

/**
 * @brief Each EventSubscriber must register itself so the init method is
 * called.
 *
 * This registers YARAEventSubscriber into the osquery EventSubscriber
 * pseudo-plugin registry.
 */
REGISTER(YARAEventSubscriber, "event_subscriber", "yara_events");

void YARAEventSubscriber::configure() {
  removeSubscriptions();

  // There is a special yara parser that tracks the related top-level keys.
  auto plugin = Config::getParser("yara");
  if (plugin == nullptr || plugin.get() == nullptr) {
    return;
  }

  // Bail if there is no configured set of opt-in paths for yara.
  const auto& yara_config = plugin->getData().doc();
  if (!yara_config.HasMember("file_paths") ||
      !yara_config["file_paths"].IsObject()) {
    return;
  }

  // Collect the set of paths, we are mostly concerned with the categories.
  // But the subscriber must duplicate the set of subscriptions such that the
  // publisher's 'fire'-matching logic routes related events to our callback.
  std::map<std::string, std::vector<std::string>> file_map;
  Config::get().files([&file_map](const std::string& category,
                                  const std::vector<std::string>& files) {
    file_map[category] = files;
  });

  // For each category within yara's file_paths, add a subscription to the
  // corresponding set of paths.
  const auto& yara_paths = yara_config["file_paths"];
  for (const auto& yara_path_element : yara_paths.GetObject()) {
    std::string category = yara_path_element.name.GetString();
    // Subscribe to each file for the given key (category).
    if (file_map.count(category) == 0) {
      VLOG(1) << "Key in YARA file_paths not found in file_paths: " << category;
      continue;
    }

    for (const auto& file : file_map.at(category)) {
      VLOG(1) << "Added YARA listener to: " << file;
      auto sc = createSubscriptionContext();
      sc->recursive = 0;
      sc->path = file;
      sc->mask = FILE_CHANGE_MASK;
      sc->category = std::move(category);
      subscribe(&YARAEventSubscriber::Callback, sc);
    }
  }
}

Status YARAEventSubscriber::Callback(const FileEventContextRef& ec,
                                     const FileSubscriptionContextRef& sc) {
  if (ec->action != "UPDATED" && ec->action != "CREATED") {
    return Status(1, "Invalid action");
  }

  Row r;
  r["action"] = ec->action;
  r["target_path"] = ec->path;
  r["category"] = sc->category;

  // Only FSEvents transactions updates (inotify is a no-op).
  r["transaction_id"] = INTEGER(ec->transaction_id);

  // These are default values, to be updated in YARACallback.
  r["count"] = INTEGER(0);
  r["matches"] = std::string("");
  r["strings"] = std::string("");
  r["tags"] = std::string("");

  auto parser = Config::getParser("yara");
  if (parser == nullptr || parser.get() == nullptr) {
    return Status(1, "ConfigParser unknown.");
  }

  std::shared_ptr<YARAConfigParserPlugin> yaraParser;
  try {
    yaraParser = std::dynamic_pointer_cast<YARAConfigParserPlugin>(parser);
  } catch (const std::bad_cast& e) {
    return Status(1, "Error casting yara config parser plugin");
  }
  if (yaraParser == nullptr || yaraParser.get() == nullptr) {
    return Status(1, "Yara parser unknown.");
  }

  auto rules = yaraParser->rules();

  // Use the category as a lookup into the yara file_paths. The value will be
  // a list of signature groups to scan with.
  auto category = r.at("category");
  const auto& yara_config = parser->getData().doc();
  const auto& yara_paths = yara_config["file_paths"];
  const auto group_iter = yara_paths.FindMember(category);
  if (group_iter != yara_paths.MemberEnd()) {
    for (const auto& rule : group_iter->value.GetArray()) {
      std::string group = rule.GetString();
      int result = yr_rules_scan_file(rules[group],
                                      ec->path.c_str(),
                                      SCAN_FLAGS_FAST_MODE,
                                      YARACallback,
                                      (void*)&r,
                                      0);

      if (result != ERROR_SUCCESS) {
        return Status(1, "YARA error: " + std::to_string(result));
      }
    }
  }

  if (ec->action != "" && !r.at("matches").empty()) {
    add(r);
  }

  return Status::success();
}
}
<commit_msg>Fix use after move in YARAEventSubscriber::configure (#6054)<commit_after>/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed in accordance with the terms specified in
 *  the LICENSE file found in the root directory of this source tree.
 */

#include <map>
#include <string>

#include <osquery/config/config.h>
#include <osquery/logger.h>
#include <osquery/registry_factory.h>
#include <osquery/tables/yara/yara_utils.h>

/// The file change event publishers are slightly different in OS X and Linux.
#ifdef __APPLE__
#include <osquery/events/darwin/fsevents.h>
#elif __linux__
#include <osquery/events/linux/inotify.h>
#endif

#ifdef CONCAT
#undef CONCAT
#endif
#include <yara.h>

namespace osquery {

/// The file change event publishers are slightly different in OS X and Linux.
#ifdef __APPLE__
using FileEventSubscriber = EventSubscriber<FSEventsEventPublisher>;
using FileEventContextRef = FSEventsEventContextRef;
using FileSubscriptionContextRef = FSEventsSubscriptionContextRef;
#define FILE_CHANGE_MASK                                                       \
  kFSEventStreamEventFlagItemCreated | kFSEventStreamEventFlagItemModified |   \
      kFSEventStreamEventFlagItemRenamed
#elif __linux__
using FileEventSubscriber = EventSubscriber<INotifyEventPublisher>;
using FileEventContextRef = INotifyEventContextRef;
using FileSubscriptionContextRef = INotifySubscriptionContextRef;
#define FILE_CHANGE_MASK                                                       \
  ((IN_CREATE) | (IN_CLOSE_WRITE) | (IN_MODIFY) | (IN_MOVED_TO))
#endif

/**
 * @brief Track YARA matches to files.
 */
class YARAEventSubscriber : public FileEventSubscriber {
 public:
  Status init() override {
    return Status(0);
  }

  void configure() override;

 private:
  /**
   * @brief This exports a single Callback for FSEventsEventPublisher events.
   *
   * @param ec The Callback type receives an EventContextRef substruct
   * for the FSEventsEventPublisher declared in this EventSubscriber subclass.
   *
   * @return Status
   */
  Status Callback(const FileEventContextRef& ec,
                  const FileSubscriptionContextRef& sc);
};

/**
 * @brief Each EventSubscriber must register itself so the init method is
 * called.
 *
 * This registers YARAEventSubscriber into the osquery EventSubscriber
 * pseudo-plugin registry.
 */
REGISTER(YARAEventSubscriber, "event_subscriber", "yara_events");

void YARAEventSubscriber::configure() {
  removeSubscriptions();

  // There is a special yara parser that tracks the related top-level keys.
  auto plugin = Config::getParser("yara");
  if (plugin == nullptr || plugin.get() == nullptr) {
    return;
  }

  // Bail if there is no configured set of opt-in paths for yara.
  const auto& yara_config = plugin->getData().doc();
  if (!yara_config.HasMember("file_paths") ||
      !yara_config["file_paths"].IsObject()) {
    return;
  }

  // Collect the set of paths, we are mostly concerned with the categories.
  // But the subscriber must duplicate the set of subscriptions such that the
  // publisher's 'fire'-matching logic routes related events to our callback.
  std::map<std::string, std::vector<std::string>> file_map;
  Config::get().files([&file_map](const std::string& category,
                                  const std::vector<std::string>& files) {
    file_map[category] = files;
  });

  // For each category within yara's file_paths, add a subscription to the
  // corresponding set of paths.
  const auto& yara_paths = yara_config["file_paths"];
  for (const auto& yara_path_element : yara_paths.GetObject()) {
    std::string category = yara_path_element.name.GetString();
    // Subscribe to each file for the given key (category).
    if (file_map.count(category) == 0) {
      VLOG(1) << "Key in YARA file_paths not found in file_paths: " << category;
      continue;
    }

    for (const auto& file : file_map.at(category)) {
      VLOG(1) << "Added YARA listener to: " << file;
      auto sc = createSubscriptionContext();
      sc->recursive = 0;
      sc->path = file;
      sc->mask = FILE_CHANGE_MASK;
      sc->category = category;
      subscribe(&YARAEventSubscriber::Callback, sc);
    }
  }
}

Status YARAEventSubscriber::Callback(const FileEventContextRef& ec,
                                     const FileSubscriptionContextRef& sc) {
  if (ec->action != "UPDATED" && ec->action != "CREATED") {
    return Status(1, "Invalid action");
  }

  Row r;
  r["action"] = ec->action;
  r["target_path"] = ec->path;
  r["category"] = sc->category;

  // Only FSEvents transactions updates (inotify is a no-op).
  r["transaction_id"] = INTEGER(ec->transaction_id);

  // These are default values, to be updated in YARACallback.
  r["count"] = INTEGER(0);
  r["matches"] = std::string("");
  r["strings"] = std::string("");
  r["tags"] = std::string("");

  auto parser = Config::getParser("yara");
  if (parser == nullptr || parser.get() == nullptr) {
    return Status(1, "ConfigParser unknown.");
  }

  std::shared_ptr<YARAConfigParserPlugin> yaraParser;
  try {
    yaraParser = std::dynamic_pointer_cast<YARAConfigParserPlugin>(parser);
  } catch (const std::bad_cast& e) {
    return Status(1, "Error casting yara config parser plugin");
  }
  if (yaraParser == nullptr || yaraParser.get() == nullptr) {
    return Status(1, "Yara parser unknown.");
  }

  auto rules = yaraParser->rules();

  // Use the category as a lookup into the yara file_paths. The value will be
  // a list of signature groups to scan with.
  auto category = r.at("category");
  const auto& yara_config = parser->getData().doc();
  const auto& yara_paths = yara_config["file_paths"];
  const auto group_iter = yara_paths.FindMember(category);
  if (group_iter != yara_paths.MemberEnd()) {
    for (const auto& rule : group_iter->value.GetArray()) {
      std::string group = rule.GetString();
      int result = yr_rules_scan_file(rules[group],
                                      ec->path.c_str(),
                                      SCAN_FLAGS_FAST_MODE,
                                      YARACallback,
                                      (void*)&r,
                                      0);

      if (result != ERROR_SUCCESS) {
        return Status(1, "YARA error: " + std::to_string(result));
      }
    }
  }

  if (ec->action != "" && !r.at("matches").empty()) {
    add(r);
  }

  return Status::success();
}
}
<|endoftext|>


<commit_before>#include "route.hpp"
#include "turns_generator.hpp"

#include "indexer/mercator.hpp"

#include "platform/location.hpp"

#include "geometry/angles.hpp"
#include "geometry/point2d.hpp"
#include "geometry/simplification.hpp"

#include "base/logging.hpp"

#include "std/numeric.hpp"
#include "std/utility.hpp"
#include "std/algorithm.hpp"

namespace routing
{
namespace
{
double constexpr kLocationTimeThreshold = 60.0 * 1.0;
double constexpr kOnEndToleranceM = 10.0;

}  //  namespace

Route::Route(string const & router, vector<m2::PointD> const & points, string const & name)
  : m_router(router), m_routingSettings(GetCarRoutingSettings()),
    m_name(name), m_poly(points.begin(), points.end())
{
  Update();
}

void Route::Swap(Route & rhs)
{
  m_router.swap(rhs.m_router);
  swap(m_routingSettings, rhs.m_routingSettings);
  m_poly.Swap(rhs.m_poly);
  m_simplifiedPoly.Swap(rhs.m_simplifiedPoly);
  m_name.swap(rhs.m_name);
  swap(m_currentTime, rhs.m_currentTime);
  swap(m_turns, rhs.m_turns);
  swap(m_times, rhs.m_times);
  m_absentCountries.swap(rhs.m_absentCountries);
}

double Route::GetTotalDistanceMeters() const
{
  return m_poly.GetTotalDistanceM();
}

double Route::GetCurrentDistanceFromBeginMeters() const
{
  return m_poly.GetDistanceFromBeginM();
}

void Route::GetTurnsDistances(vector<double> & distances) const
{
  double mercatorDistance = 0;
  distances.clear();
  auto const & polyline = m_poly.GetPolyline();
  for (auto currentTurn = m_turns.begin(); currentTurn != m_turns.end(); ++currentTurn)
  {
    // Skip turns at side points of the polyline geometry. We can't display them properly.
    if (currentTurn->m_index == 0 || currentTurn->m_index == (polyline.GetSize() - 1))
      continue;

    uint32_t formerTurnIndex = 0;
    if (currentTurn != m_turns.begin())
      formerTurnIndex = (currentTurn - 1)->m_index;

    //TODO (ldragunov) Extract CalculateMercatorDistance higher to avoid including turns generator.
    double const mercatorDistanceBetweenTurns =
      turns::CalculateMercatorDistanceAlongPath(formerTurnIndex,  currentTurn->m_index, polyline.GetPoints());
    mercatorDistance += mercatorDistanceBetweenTurns;

    distances.push_back(mercatorDistance);
   }
}

double Route::GetCurrentDistanceToEndMeters() const
{
  return m_poly.GetDistanceToEndM();
}

double Route::GetMercatorDistanceFromBegin() const
{
  //TODO Maybe better to return FollowedRoute and user will call GetMercatorDistance etc. by itself
  return m_poly.GetMercatorDistanceFromBegin();
}

uint32_t Route::GetTotalTimeSec() const
{
  return m_times.empty() ? 0 : m_times.back().second;
}

uint32_t Route::GetCurrentTimeToEndSec() const
{
  size_t const polySz = m_poly.GetPolyline().GetSize();
  if (m_times.empty() || polySz == 0)
  {
    ASSERT(!m_times.empty(), ());
    ASSERT(polySz != 0, ());
    return 0;
  }

  TTimes::const_iterator it = upper_bound(m_times.begin(), m_times.end(), m_poly.GetCurrentIter().m_ind,
                                         [](size_t v, Route::TTimeItem const & item) { return v < item.first; });

  if (it == m_times.end())
    return 0;

  size_t idx = distance(m_times.begin(), it);
  double time = (*it).second;
  if (idx > 0)
    time -= m_times[idx - 1].second;

  auto distFn = [&](size_t start, size_t end)
  {
    return m_poly.GetDistanceM(m_poly.GetIterToIndex(start), m_poly.GetIterToIndex(end));
  };

  ASSERT_LESS(m_times[idx].first, polySz, ());
  double const dist = distFn(idx > 0 ? m_times[idx - 1].first : 0, m_times[idx].first);

  if (!my::AlmostEqualULPs(dist, 0.))
  {
    double const distRemain = distFn(m_poly.GetCurrentIter().m_ind, m_times[idx].first) -
                                     MercatorBounds::DistanceOnEarth(m_poly.GetCurrentIter().m_pt,
                                     m_poly.GetPolyline().GetPoint(m_poly.GetCurrentIter().m_ind));
    return (uint32_t)((GetTotalTimeSec() - (*it).second) + (double)time * (distRemain / dist));
  }
  else
    return (uint32_t)((GetTotalTimeSec() - (*it).second));
}

Route::TTurns::const_iterator Route::GetCurrentTurn() const
{
  ASSERT(!m_turns.empty(), ());

  turns::TurnItem t;
  t.m_index = static_cast<uint32_t>(m_poly.GetCurrentIter().m_ind);
  return upper_bound(m_turns.cbegin(), m_turns.cend(), t,
         [](turns::TurnItem const & lhs, turns::TurnItem const & rhs)
         {
           return lhs.m_index < rhs.m_index;
         });
}

// @TODO After current GPS possition passes the finish of the route the method GetCurrentTurn
// continues returning the last turn of the route. It looks like an issue.
bool Route::GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const
{
  auto it = GetCurrentTurn();
  if (it == m_turns.end())
  {
    ASSERT(it != m_turns.end(), ());
    distanceToTurnMeters = 0;
    turn = turns::TurnItem();
    return false;
  }

  size_t const segIdx = (*it).m_index;
  turn = (*it);
  distanceToTurnMeters = m_poly.GetDistanceM(m_poly.GetCurrentIter(),
                                             m_poly.GetIterToIndex(segIdx));
  return true;
}

bool Route::GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const
{
  auto it = GetCurrentTurn();
  auto const turnsEnd = m_turns.end();
  ASSERT(it != turnsEnd, ());

  if (it == turnsEnd || (it + 1) == turnsEnd)
  {
    turn = turns::TurnItem();
    distanceToTurnMeters = 0;
    return false;
  }

  it += 1;
  turn = *it;
  distanceToTurnMeters = m_poly.GetDistanceM(m_poly.GetCurrentIter(),
                                             m_poly.GetIterToIndex(it->m_index));
  return true;
}

bool Route::GetNextTurns(vector<turns::TurnItemDist> & turns)
{
  turns.clear();

  turns::TurnItemDist currentTurn;
  if (!GetCurrentTurn(currentTurn.m_distMeters, currentTurn.m_turnItem))
    return false;
  turns.push_back(move(currentTurn));

  turns::TurnItemDist nextTurn;
  if (!GetNextTurn(nextTurn.m_distMeters, nextTurn.m_turnItem))
    return false;
  turns.push_back(move(nextTurn));
  return true;
}

void Route::GetCurrentDirectionPoint(m2::PointD & pt) const
{
  if (m_routingSettings.m_keepPedestrianInfo && m_simplifiedPoly.IsValid())
    m_simplifiedPoly.GetCurrentDirectionPoint(pt, kOnEndToleranceM);
  else
    m_poly.GetCurrentDirectionPoint(pt, kOnEndToleranceM);
}

bool Route::MoveIterator(location::GpsInfo const & info) const
{
  double predictDistance = -1.0;
  if (m_currentTime > 0.0 && info.HasSpeed())
  {
    /// @todo Need to distinguish GPS and WiFi locations.
    /// They may have different time metrics in case of incorrect system time on a device.
    double const deltaT = info.m_timestamp - m_currentTime;
    if (deltaT > 0.0 && deltaT < kLocationTimeThreshold)
      predictDistance = info.m_speed * deltaT;
  }

  m2::RectD const rect = MercatorBounds::MetresToXY(
        info.m_longitude, info.m_latitude,
        max(m_routingSettings.m_matchingThresholdM, info.m_horizontalAccuracy));
  FollowedPolyline::Iter const res = m_poly.UpdateProjectionByPrediction(rect, predictDistance);
  if (m_simplifiedPoly.IsValid())
    m_simplifiedPoly.UpdateProjectionByPrediction(rect, predictDistance);
  return res.IsValid();
}

double Route::GetCurrentSqDistance(m2::PointD const & pt) const
{
  ASSERT(m_poly.IsValid(), ());
  return pt.SquareLength(m_poly.GetCurrentIter().m_pt);
}

double Route::GetPolySegAngle(size_t ind) const
{
  size_t const polySz = m_poly.GetPolyline().GetSize();

  if (ind + 1 >= polySz)
  {
    ASSERT(false, ());
    return 0;
  }

  m2::PointD const p1 = m_poly.GetPolyline().GetPoint(ind);
  m2::PointD p2;
  size_t i = ind + 1;
  do
  {
    p2 = m_poly.GetPolyline().GetPoint(i);
  }
  while (m2::AlmostEqualULPs(p1, p2) && ++i < polySz);
  return (i == polySz) ? 0 : my::RadToDeg(ang::AngleTo(p1, p2));
}

void Route::MatchLocationToRoute(location::GpsInfo & location, location::RouteMatchingInfo & routeMatchingInfo) const
{
  if (m_poly.IsValid())
  {
    auto const & iter = m_poly.GetCurrentIter();
    m2::PointD const locationMerc = MercatorBounds::FromLatLon(location.m_latitude, location.m_longitude);
    double const distFromRouteM = MercatorBounds::DistanceOnEarth(iter.m_pt, locationMerc);
    if (distFromRouteM < m_routingSettings.m_matchingThresholdM)
    {
      location.m_latitude = MercatorBounds::YToLat(iter.m_pt.y);
      location.m_longitude = MercatorBounds::XToLon(iter.m_pt.x);
      if (m_routingSettings.m_matchRoute)
        location.m_bearing = location::AngleToBearing(GetPolySegAngle(iter.m_ind));

      routeMatchingInfo.Set(iter.m_pt, iter.m_ind);
    }
  }
}

bool Route::IsCurrentOnEnd() const
{
  return (m_poly.GetDistanceToEndM() < kOnEndToleranceM);
}

void Route::Update()
{
  if (!m_poly.IsValid())
    return;
  if (m_routingSettings.m_keepPedestrianInfo)
  {
    vector<m2::PointD> points;
    auto distFn = m2::DistanceToLineSquare<m2::PointD>();
    // TODO (ldargunov) Rewrite dist f to distance in meters and avoid 0.00000 constants.
    SimplifyNearOptimal(20, m_poly.GetPolyline().Begin(), m_poly.GetPolyline().End(), 0.00000001, distFn,
                        MakeBackInsertFunctor(points));
    FollowedPolyline(points.begin(), points.end()).Swap(m_simplifiedPoly);
  }
  else
  {
    // Free memory if we don't need simplified geometry.
    FollowedPolyline().Swap(m_simplifiedPoly);
  }
  m_currentTime = 0.0;
}

string DebugPrint(Route const & r)
{
  return DebugPrint(r.m_poly.GetPolyline());
}

} // namespace routing
<commit_msg>GetNextTurns returns true if at least the first next turn is valid.<commit_after>#include "route.hpp"
#include "turns_generator.hpp"

#include "indexer/mercator.hpp"

#include "platform/location.hpp"

#include "geometry/angles.hpp"
#include "geometry/point2d.hpp"
#include "geometry/simplification.hpp"

#include "base/logging.hpp"

#include "std/numeric.hpp"
#include "std/utility.hpp"
#include "std/algorithm.hpp"

namespace routing
{
namespace
{
double constexpr kLocationTimeThreshold = 60.0 * 1.0;
double constexpr kOnEndToleranceM = 10.0;

}  //  namespace

Route::Route(string const & router, vector<m2::PointD> const & points, string const & name)
  : m_router(router), m_routingSettings(GetCarRoutingSettings()),
    m_name(name), m_poly(points.begin(), points.end())
{
  Update();
}

void Route::Swap(Route & rhs)
{
  m_router.swap(rhs.m_router);
  swap(m_routingSettings, rhs.m_routingSettings);
  m_poly.Swap(rhs.m_poly);
  m_simplifiedPoly.Swap(rhs.m_simplifiedPoly);
  m_name.swap(rhs.m_name);
  swap(m_currentTime, rhs.m_currentTime);
  swap(m_turns, rhs.m_turns);
  swap(m_times, rhs.m_times);
  m_absentCountries.swap(rhs.m_absentCountries);
}

double Route::GetTotalDistanceMeters() const
{
  return m_poly.GetTotalDistanceM();
}

double Route::GetCurrentDistanceFromBeginMeters() const
{
  return m_poly.GetDistanceFromBeginM();
}

void Route::GetTurnsDistances(vector<double> & distances) const
{
  double mercatorDistance = 0;
  distances.clear();
  auto const & polyline = m_poly.GetPolyline();
  for (auto currentTurn = m_turns.begin(); currentTurn != m_turns.end(); ++currentTurn)
  {
    // Skip turns at side points of the polyline geometry. We can't display them properly.
    if (currentTurn->m_index == 0 || currentTurn->m_index == (polyline.GetSize() - 1))
      continue;

    uint32_t formerTurnIndex = 0;
    if (currentTurn != m_turns.begin())
      formerTurnIndex = (currentTurn - 1)->m_index;

    //TODO (ldragunov) Extract CalculateMercatorDistance higher to avoid including turns generator.
    double const mercatorDistanceBetweenTurns =
      turns::CalculateMercatorDistanceAlongPath(formerTurnIndex,  currentTurn->m_index, polyline.GetPoints());
    mercatorDistance += mercatorDistanceBetweenTurns;

    distances.push_back(mercatorDistance);
   }
}

double Route::GetCurrentDistanceToEndMeters() const
{
  return m_poly.GetDistanceToEndM();
}

double Route::GetMercatorDistanceFromBegin() const
{
  //TODO Maybe better to return FollowedRoute and user will call GetMercatorDistance etc. by itself
  return m_poly.GetMercatorDistanceFromBegin();
}

uint32_t Route::GetTotalTimeSec() const
{
  return m_times.empty() ? 0 : m_times.back().second;
}

uint32_t Route::GetCurrentTimeToEndSec() const
{
  size_t const polySz = m_poly.GetPolyline().GetSize();
  if (m_times.empty() || polySz == 0)
  {
    ASSERT(!m_times.empty(), ());
    ASSERT(polySz != 0, ());
    return 0;
  }

  TTimes::const_iterator it = upper_bound(m_times.begin(), m_times.end(), m_poly.GetCurrentIter().m_ind,
                                         [](size_t v, Route::TTimeItem const & item) { return v < item.first; });

  if (it == m_times.end())
    return 0;

  size_t idx = distance(m_times.begin(), it);
  double time = (*it).second;
  if (idx > 0)
    time -= m_times[idx - 1].second;

  auto distFn = [&](size_t start, size_t end)
  {
    return m_poly.GetDistanceM(m_poly.GetIterToIndex(start), m_poly.GetIterToIndex(end));
  };

  ASSERT_LESS(m_times[idx].first, polySz, ());
  double const dist = distFn(idx > 0 ? m_times[idx - 1].first : 0, m_times[idx].first);

  if (!my::AlmostEqualULPs(dist, 0.))
  {
    double const distRemain = distFn(m_poly.GetCurrentIter().m_ind, m_times[idx].first) -
                                     MercatorBounds::DistanceOnEarth(m_poly.GetCurrentIter().m_pt,
                                     m_poly.GetPolyline().GetPoint(m_poly.GetCurrentIter().m_ind));
    return (uint32_t)((GetTotalTimeSec() - (*it).second) + (double)time * (distRemain / dist));
  }
  else
    return (uint32_t)((GetTotalTimeSec() - (*it).second));
}

Route::TTurns::const_iterator Route::GetCurrentTurn() const
{
  ASSERT(!m_turns.empty(), ());

  turns::TurnItem t;
  t.m_index = static_cast<uint32_t>(m_poly.GetCurrentIter().m_ind);
  return upper_bound(m_turns.cbegin(), m_turns.cend(), t,
         [](turns::TurnItem const & lhs, turns::TurnItem const & rhs)
         {
           return lhs.m_index < rhs.m_index;
         });
}

// @TODO After current GPS possition passes the finish of the route the method GetCurrentTurn
// continues returning the last turn of the route. It looks like an issue.
bool Route::GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const
{
  auto it = GetCurrentTurn();
  if (it == m_turns.end())
  {
    ASSERT(it != m_turns.end(), ());
    distanceToTurnMeters = 0;
    turn = turns::TurnItem();
    return false;
  }

  size_t const segIdx = (*it).m_index;
  turn = (*it);
  distanceToTurnMeters = m_poly.GetDistanceM(m_poly.GetCurrentIter(),
                                             m_poly.GetIterToIndex(segIdx));
  return true;
}

bool Route::GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const
{
  auto it = GetCurrentTurn();
  auto const turnsEnd = m_turns.end();
  ASSERT(it != turnsEnd, ());

  if (it == turnsEnd || (it + 1) == turnsEnd)
  {
    turn = turns::TurnItem();
    distanceToTurnMeters = 0;
    return false;
  }

  it += 1;
  turn = *it;
  distanceToTurnMeters = m_poly.GetDistanceM(m_poly.GetCurrentIter(),
                                             m_poly.GetIterToIndex(it->m_index));
  return true;
}

bool Route::GetNextTurns(vector<turns::TurnItemDist> & turns)
{
  turns.clear();

  turns::TurnItemDist currentTurn;
  if (!GetCurrentTurn(currentTurn.m_distMeters, currentTurn.m_turnItem))
    return false;
  turns.push_back(move(currentTurn));

  turns::TurnItemDist nextTurn;
  if (!GetNextTurn(nextTurn.m_distMeters, nextTurn.m_turnItem))
    return true;
  turns.push_back(move(nextTurn));
  return true;
}

void Route::GetCurrentDirectionPoint(m2::PointD & pt) const
{
  if (m_routingSettings.m_keepPedestrianInfo && m_simplifiedPoly.IsValid())
    m_simplifiedPoly.GetCurrentDirectionPoint(pt, kOnEndToleranceM);
  else
    m_poly.GetCurrentDirectionPoint(pt, kOnEndToleranceM);
}

bool Route::MoveIterator(location::GpsInfo const & info) const
{
  double predictDistance = -1.0;
  if (m_currentTime > 0.0 && info.HasSpeed())
  {
    /// @todo Need to distinguish GPS and WiFi locations.
    /// They may have different time metrics in case of incorrect system time on a device.
    double const deltaT = info.m_timestamp - m_currentTime;
    if (deltaT > 0.0 && deltaT < kLocationTimeThreshold)
      predictDistance = info.m_speed * deltaT;
  }

  m2::RectD const rect = MercatorBounds::MetresToXY(
        info.m_longitude, info.m_latitude,
        max(m_routingSettings.m_matchingThresholdM, info.m_horizontalAccuracy));
  FollowedPolyline::Iter const res = m_poly.UpdateProjectionByPrediction(rect, predictDistance);
  if (m_simplifiedPoly.IsValid())
    m_simplifiedPoly.UpdateProjectionByPrediction(rect, predictDistance);
  return res.IsValid();
}

double Route::GetCurrentSqDistance(m2::PointD const & pt) const
{
  ASSERT(m_poly.IsValid(), ());
  return pt.SquareLength(m_poly.GetCurrentIter().m_pt);
}

double Route::GetPolySegAngle(size_t ind) const
{
  size_t const polySz = m_poly.GetPolyline().GetSize();

  if (ind + 1 >= polySz)
  {
    ASSERT(false, ());
    return 0;
  }

  m2::PointD const p1 = m_poly.GetPolyline().GetPoint(ind);
  m2::PointD p2;
  size_t i = ind + 1;
  do
  {
    p2 = m_poly.GetPolyline().GetPoint(i);
  }
  while (m2::AlmostEqualULPs(p1, p2) && ++i < polySz);
  return (i == polySz) ? 0 : my::RadToDeg(ang::AngleTo(p1, p2));
}

void Route::MatchLocationToRoute(location::GpsInfo & location, location::RouteMatchingInfo & routeMatchingInfo) const
{
  if (m_poly.IsValid())
  {
    auto const & iter = m_poly.GetCurrentIter();
    m2::PointD const locationMerc = MercatorBounds::FromLatLon(location.m_latitude, location.m_longitude);
    double const distFromRouteM = MercatorBounds::DistanceOnEarth(iter.m_pt, locationMerc);
    if (distFromRouteM < m_routingSettings.m_matchingThresholdM)
    {
      location.m_latitude = MercatorBounds::YToLat(iter.m_pt.y);
      location.m_longitude = MercatorBounds::XToLon(iter.m_pt.x);
      if (m_routingSettings.m_matchRoute)
        location.m_bearing = location::AngleToBearing(GetPolySegAngle(iter.m_ind));

      routeMatchingInfo.Set(iter.m_pt, iter.m_ind);
    }
  }
}

bool Route::IsCurrentOnEnd() const
{
  return (m_poly.GetDistanceToEndM() < kOnEndToleranceM);
}

void Route::Update()
{
  if (!m_poly.IsValid())
    return;
  if (m_routingSettings.m_keepPedestrianInfo)
  {
    vector<m2::PointD> points;
    auto distFn = m2::DistanceToLineSquare<m2::PointD>();
    // TODO (ldargunov) Rewrite dist f to distance in meters and avoid 0.00000 constants.
    SimplifyNearOptimal(20, m_poly.GetPolyline().Begin(), m_poly.GetPolyline().End(), 0.00000001, distFn,
                        MakeBackInsertFunctor(points));
    FollowedPolyline(points.begin(), points.end()).Swap(m_simplifiedPoly);
  }
  else
  {
    // Free memory if we don't need simplified geometry.
    FollowedPolyline().Swap(m_simplifiedPoly);
  }
  m_currentTime = 0.0;
}

string DebugPrint(Route const & r)
{
  return DebugPrint(r.m_poly.GetPolyline());
}

} // namespace routing
<|endoftext|>


<commit_before>/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Nathan McCrina
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#include "TuxedoCat.h"
#include <iostream>
#include <sstream>
#include <thread>

using namespace TuxedoCat;

extern struct Board currentPosition;
static bool winboardMode;
static bool shouldQuitProgram;
static bool readyForInput;
static bool inputAvailable;
static bool showPrompt;
static bool forceMode;
static bool computerIsBlack;

static std::string input;

void Interface::ReadInput()
{
	while (true)
	{
		if (readyForInput)
		{
			readyForInput = false;

			if (showPrompt)
			{
				std::cout << "tuxedocat: ";
			}

			std::getline(std::cin, input);

			inputAvailable = true;
		}

		if (shouldQuitProgram)
		{
			break;
		}
	}
}

void Interface::OutputFeatures()
{
	std::stringstream features;

	features << "feature done=0" << std::endl;
	features << "feature setboard=1" << std::endl;
	features << "feature usermove=1" << std::endl;
	features << "feature playother=1" << std::endl;
	features << "feature analyze=0" << std::endl;
	features << "feature sigint=0" << std::endl;
	features << "feature sigterm=0" << std::endl;
	features << "feature time=0" << std::endl;
	features << "feature san=0" << std::endl;
	features << "feature ping=1" << std::endl;
	features << "feature myname=\"TuxedoCat\"" << std::endl;
	features << "feature variants=\"normal\"" << std::endl;
	features << "feature done=1" << std::endl;

	std::cout << features.str();
	Utility::WriteLog("engine -> interface: " + features.str());
}

void Interface::Run()
{
	shouldQuitProgram = false;
	readyForInput = true;
	inputAvailable = false;
	winboardMode = false;
	showPrompt = true;
	forceMode = false;
	bool computerIsBlack = true;
	std::string command;
	std::stringstream output;
	std::stringstream ss;

	Engine::InitializeEngine();

	std::thread inputThread(ReadInput);

	while (!shouldQuitProgram)
	{
		if (inputAvailable)
		{
			inputAvailable = false;

			ss.str(input);

			ss >> command;

			if (command == "quit")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				shouldQuitProgram = true;
			}
			else if (command == "xboard")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				winboardMode = true;
				showPrompt = false;

				std::cout << std::endl;

				readyForInput = true;
			}
			else if (command == "protover")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				OutputFeatures();

				readyForInput = true;
			}
			else if (command == "new")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				Engine::InitializeEngine();
				forceMode = false;
				readyForInput = true;
			}
			else if (command == "go")
			{
				forceMode = false;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (currentPosition.ColorToMove == PieceColor::WHITE)
				{
					computerIsBlack = false;
				}
				else
				{
					computerIsBlack = true;
				}

				std::string move = Engine::GetMove(currentPosition);

				if (move == "")
				{
					if (Engine::IsGameOver(currentPosition))
					{
						output << Engine::GetGameResult(currentPosition);
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
				}
				else
				{
					if (Engine::IsGameOver(currentPosition))
					{
						output << Engine::GetGameResult(currentPosition);
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
					else
					{
						output << "move " << move;
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
				}

				readyForInput = true;
			}
			else if (command == "playother")
			{
				forceMode = false;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (currentPosition.ColorToMove == PieceColor::WHITE)
				{
					computerIsBlack = true;
				}
				else
				{
					computerIsBlack = false;
				}

				readyForInput = true;
			}
			else if (command == "ping")
			{
				int value;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (ss >> value)
				{
					output << "pong " << value;
					std::cout << output.str() << std::endl;

					Utility::WriteLog("engine -> interface: " + output.str());
					output.clear();
					output.str("");
				}

				readyForInput = true;
			}
			else if (command == "perft")
			{
				int depth;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (ss >> depth)
				{
					output << "Perft (" << depth << "): " << Engine::Perft(currentPosition, depth);
					std::cout << output.str() << std::endl;

					Utility::WriteLog("engine -> interface: " + output.str());
					output.clear();
					output.str("");
				}
				else
				{
					output << "Error: depth parameter required";
					std::cout << output.str() << std::endl;

					Utility::WriteLog("engine -> interface: " + output.str());
					output.clear();
					output.str("");
				}

				readyForInput = true;
			}
			else if (command == "divide")
			{
				int depth;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (ss >> depth)
				{
					Engine::Divide(currentPosition, depth);
				}
				else
				{
					output << "Error: depth parameter required";
					std::cout << output.str() << std::endl;

					Utility::WriteLog("engine -> interface: " + output.str());
					output.clear();
					output.str("");
				}

				readyForInput = true;
			}
			else if (command == "setboard")
			{
				std::string fenPart;
				std::stringstream fen;
				int fenPartCount = 0;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				while (fenPartCount < 6)
				{
					if (ss >> fenPart)
					{
						fen << fenPart;

						if (fenPartCount < 5)
						{
							fen << " ";
						}

						fenPartCount++;
					}
					else
					{
						break;
					}
				}

				if (fenPartCount < 6)
				{
					if (winboardMode)
					{
						Utility::WriteLog("Error: Invalid FEN received");
					}
					else
					{
						output << "Error: Invalid FEN received";
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
				}
				else
				{
					Position::SetPosition(currentPosition, fen.str());
				}

				readyForInput = true;
			}
			else if (command == "usermove")
			{
				std::string moveNotation;
				TuxedoCat::Move move;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (ss >> moveNotation)
				{
					if (moveNotation.length() < 4)
					{
						output << "Error (ambiguous move): " << moveNotation;
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
					else
					{
						move = Utility::GetMoveFromXBoardNotation(currentPosition, moveNotation);

						if (move.TargetLocation == 0)
						{
							output << "Illegal move: " << moveNotation;
							std::cout << output.str() << std::endl;

							Utility::WriteLog("engine -> interface: " + output.str());
							output.clear();
							output.str("");
						}
						else
						{
							Position::Make(currentPosition, move);

							if (!forceMode)
							{
								std::string move = Engine::GetMove(currentPosition);

								if (move == "")
								{
									if (Engine::IsGameOver(currentPosition))
									{
										output << Engine::GetGameResult(currentPosition);
										std::cout << output.str() << std::endl;

										Utility::WriteLog("engine -> interface: " + output.str());
										output.clear();
										output.str("");
									}
								}
								else
								{
									if (Engine::IsGameOver(currentPosition))
									{
										output << "move " << move;
										std::cout << output.str() << std::endl;

										Utility::WriteLog("engine -> interface: " + output.str());
										output.clear();
										output.str("");

										output << Engine::GetGameResult(currentPosition);
										std::cout << output.str() << std::endl;

										Utility::WriteLog("engine -> interface: " + output.str());
										output.clear();
										output.str("");
									}
									else
									{
										output << "move " << move;
										std::cout << output.str() << std::endl;

										Utility::WriteLog("engine -> interface: " + output.str());
										output.clear();
										output.str("");
									}
								}
							}
						}
					}
				}

				readyForInput = true;
			}
			else if (command == "force")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				forceMode = true;
				readyForInput = true;
			}
			else if (command == "test")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				Test::TestPerft();
			}
			else
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				readyForInput = true;
			}

			ss.clear();
			ss.str("");
			output.clear();
			output.str("");
			input = "";
			command = "";
		}
	}

	if (inputThread.joinable())
	{
		inputThread.join();
	}
}<commit_msg>fix for threading issues<commit_after>/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Nathan McCrina
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#include "TuxedoCat.h"
#include <iostream>
#include <sstream>
#include <thread>
#include <condition_variable>
#include <mutex>

using namespace TuxedoCat;

extern struct Board currentPosition;
static bool quitProgram;
static bool winboardMode;
static bool readyForInput;
static bool inputAvailable;
static bool showPrompt;
static bool forceMode;
static bool computerIsBlack;

static std::mutex readyForInputMutex;
static std::mutex inputAvailableMutex;
static std::mutex quitProgramMutex;

static std::string input;

void Interface::ReadInput()
{
	bool shouldGo;
	bool killThread;

	while (true)
	{
		readyForInputMutex.lock();
		shouldGo = readyForInput;
		readyForInput = false;
		readyForInputMutex.unlock();

		if (shouldGo)
		{
			if (showPrompt)
			{
				std::cout << "tuxedocat: ";
			}

			std::getline(std::cin, input);

			inputAvailableMutex.lock();
			inputAvailable = true;
			inputAvailableMutex.unlock();
		}

		quitProgramMutex.lock();
		killThread = quitProgram;
		quitProgramMutex.unlock();

		if (killThread)
		{
			break;
		}
	}
}

void Interface::OutputFeatures()
{
	std::stringstream features;

	features << "feature done=0" << std::endl;
	features << "feature setboard=1" << std::endl;
	features << "feature usermove=1" << std::endl;
	features << "feature playother=1" << std::endl;
	features << "feature analyze=0" << std::endl;
	features << "feature sigint=0" << std::endl;
	features << "feature sigterm=0" << std::endl;
	features << "feature time=0" << std::endl;
	features << "feature san=0" << std::endl;
	features << "feature ping=1" << std::endl;
	features << "feature myname=\"TuxedoCat\"" << std::endl;
	features << "feature variants=\"normal\"" << std::endl;
	features << "feature done=1" << std::endl;

	std::cout << features.str();
	Utility::WriteLog("engine -> interface: " + features.str());
}

void Interface::Run()
{
	readyForInput = true;
	inputAvailable = false;
	winboardMode = false;
	showPrompt = true;
	forceMode = false;
	bool computerIsBlack = true;
	bool shouldGo;
	std::string command;
	std::stringstream output;
	std::stringstream ss;

	Engine::InitializeEngine();

	std::thread inputThread(ReadInput);

	while (true)
	{
		inputAvailableMutex.lock();
		shouldGo = inputAvailable;
		inputAvailable = false;
		inputAvailableMutex.unlock();

		if (shouldGo)
		{
			ss.str(input);

			ss >> command;

			if (command == "quit")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				quitProgramMutex.lock();
				quitProgram = true;
				quitProgramMutex.unlock();

				break;
			}
			else if (command == "xboard")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				winboardMode = true;
				showPrompt = false;

				std::cout << std::endl;
			}
			else if (command == "protover")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				OutputFeatures();
			}
			else if (command == "new")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				Engine::InitializeEngine();
				forceMode = false;
			}
			else if (command == "go")
			{
				forceMode = false;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (currentPosition.ColorToMove == PieceColor::WHITE)
				{
					computerIsBlack = false;
				}
				else
				{
					computerIsBlack = true;
				}

				std::string move = Engine::GetMove(currentPosition);

				if (move == "")
				{
					if (Engine::IsGameOver(currentPosition))
					{
						output << Engine::GetGameResult(currentPosition);
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
				}
				else
				{
					if (Engine::IsGameOver(currentPosition))
					{
						output << Engine::GetGameResult(currentPosition);
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
					else
					{
						output << "move " << move;
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
				}
			}
			else if (command == "playother")
			{
				forceMode = false;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (currentPosition.ColorToMove == PieceColor::WHITE)
				{
					computerIsBlack = true;
				}
				else
				{
					computerIsBlack = false;
				}
			}
			else if (command == "ping")
			{
				int value;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (ss >> value)
				{
					output << "pong " << value;
					std::cout << output.str() << std::endl;

					Utility::WriteLog("engine -> interface: " + output.str());
					output.clear();
					output.str("");
				}
			}
			else if (command == "perft")
			{
				int depth;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (ss >> depth)
				{
					output << "Perft (" << depth << "): " << Engine::Perft(currentPosition, depth);
					std::cout << output.str() << std::endl;

					Utility::WriteLog("engine -> interface: " + output.str());
					output.clear();
					output.str("");
				}
				else
				{
					output << "Error: depth parameter required";
					std::cout << output.str() << std::endl;

					Utility::WriteLog("engine -> interface: " + output.str());
					output.clear();
					output.str("");
				}
			}
			else if (command == "divide")
			{
				int depth;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (ss >> depth)
				{
					Engine::Divide(currentPosition, depth);
				}
				else
				{
					output << "Error: depth parameter required";
					std::cout << output.str() << std::endl;

					Utility::WriteLog("engine -> interface: " + output.str());
					output.clear();
					output.str("");
				}
			}
			else if (command == "setboard")
			{
				std::string fenPart;
				std::stringstream fen;
				int fenPartCount = 0;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				while (fenPartCount < 6)
				{
					if (ss >> fenPart)
					{
						fen << fenPart;

						if (fenPartCount < 5)
						{
							fen << " ";
						}

						fenPartCount++;
					}
					else
					{
						break;
					}
				}

				if (fenPartCount < 6)
				{
					if (winboardMode)
					{
						Utility::WriteLog("Error: Invalid FEN received");
					}
					else
					{
						output << "Error: Invalid FEN received";
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
				}
				else
				{
					Position::SetPosition(currentPosition, fen.str());
				}
			}
			else if (command == "usermove")
			{
				std::string moveNotation;
				TuxedoCat::Move move;

				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				if (ss >> moveNotation)
				{
					if (moveNotation.length() < 4)
					{
						output << "Error (ambiguous move): " << moveNotation;
						std::cout << output.str() << std::endl;

						Utility::WriteLog("engine -> interface: " + output.str());
						output.clear();
						output.str("");
					}
					else
					{
						move = Utility::GetMoveFromXBoardNotation(currentPosition, moveNotation);

						if (move.TargetLocation == 0)
						{
							output << "Illegal move: " << moveNotation;
							std::cout << output.str() << std::endl;

							Utility::WriteLog("engine -> interface: " + output.str());
							output.clear();
							output.str("");
						}
						else
						{
							Position::Make(currentPosition, move);

							if (!forceMode)
							{
								std::string move = Engine::GetMove(currentPosition);

								if (move == "")
								{
									if (Engine::IsGameOver(currentPosition))
									{
										output << Engine::GetGameResult(currentPosition);
										std::cout << output.str() << std::endl;

										Utility::WriteLog("engine -> interface: " + output.str());
										output.clear();
										output.str("");
									}
								}
								else
								{
									if (Engine::IsGameOver(currentPosition))
									{
										output << "move " << move;
										std::cout << output.str() << std::endl;

										Utility::WriteLog("engine -> interface: " + output.str());
										output.clear();
										output.str("");

										output << Engine::GetGameResult(currentPosition);
										std::cout << output.str() << std::endl;

										Utility::WriteLog("engine -> interface: " + output.str());
										output.clear();
										output.str("");
									}
									else
									{
										output << "move " << move;
										std::cout << output.str() << std::endl;

										Utility::WriteLog("engine -> interface: " + output.str());
										output.clear();
										output.str("");
									}
								}
							}
						}
					}
				}
			}
			else if (command == "force")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				forceMode = true;
			}
			else if (command == "test")
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");

				Test::TestPerft();
			}
			else
			{
				output << "interface -> engine: " << input;
				Utility::WriteLog(output.str());
				output.clear();
				output.str("");
			}

			ss.clear();
			ss.str("");
			output.clear();
			output.str("");
			input = "";
			command = "";

			readyForInputMutex.lock();
			readyForInput = true;
			readyForInputMutex.unlock();
		}
	}

	if (inputThread.joinable())
	{
		inputThread.join();
	}
}<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#include "APIGrammar.h"
#include "RequestHandler.h"
#include "Http/Request.h"

#include "../DataStructures/JSONContainer.h"
#include "../Library/OSRM.h"
#include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h"
#include "../typedefs.h"

#include <osrm/Reply.h>
#include <osrm/RouteParameters.h>

#include <ctime>

#include <algorithm>
#include <iostream>

RequestHandler::RequestHandler() : routing_machine(nullptr) {}

void RequestHandler::handle_request(const http::Request &req, http::Reply &reply)
{
    // parse command
    try
    {
        std::string request;
        URIDecode(req.uri, request);

        // deactivated as GCC apparently does not implement that, not even in 4.9
        // std::time_t t = std::time(nullptr);
        // SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
        //     " " << req.endpoint.to_string() << " " <<
        //     req.referrer << ( 0 == req.referrer.length() ? "- " :" ") <<
        //     req.agent << ( 0 == req.agent.length() ? "- " :" ") << request;

        time_t ltime;
        struct tm *Tm;

        ltime = time(nullptr);
        Tm = localtime(&ltime);

        // log timestamp
        SimpleLogger().Write() << (Tm->tm_mday < 10 ? "0" : "") << Tm->tm_mday << "-"
                               << (Tm->tm_mon + 1 < 10 ? "0" : "") << (Tm->tm_mon + 1) << "-"
                               << 1900 + Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "")
                               << Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "") << Tm->tm_min
                               << ":" << (Tm->tm_sec < 10 ? "0" : "") << Tm->tm_sec << " "
                               << req.endpoint.to_string() << " " << req.referrer
                               << (0 == req.referrer.length() ? "- " : " ") << req.agent
                               << (0 == req.agent.length() ? "- " : " ") << request;

        RouteParameters route_parameters;
        APIGrammarParser api_parser(&route_parameters);

        auto iter = request.begin();
        const bool result = boost::spirit::qi::parse(iter, request.end(), api_parser);

        // check if the was an error with the request
        if (!result || (iter != request.end()))
        {
            reply = http::Reply::StockReply(http::Reply::badRequest);
            reply.content.clear();
            const unsigned position = static_cast<unsigned>(std::distance(request.begin(), iter));
            JSON::Object json_result;
            json_result.values["status"] = 400;
            std::string message = "Query string malformed close to position ";
            message += UintToString(position);
            json_result.values["status_message"] = message;
            JSON::render(reply.content, json_result);
            return;
        }

        // parsing done, lets call the right plugin to handle the request
        BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");

        if (!route_parameters.jsonp_parameter.empty())
        {   // prepend response with jsonp parameter
            const std::string json_p = (route_parameters.jsonp_parameter + "(");
            reply.content.insert(reply.content.end(), json_p.begin(), json_p.end());
        }
        routing_machine->RunQuery(route_parameters, reply);
        if (!route_parameters.jsonp_parameter.empty())
        {   // append brace to jsonp response
            reply.content.push_back(')');
        }

        // set headers
        reply.headers.emplace_back("Content-Length", UintToString(static_cast<unsigned>(reply.content.size())));
        if ("gpx" == route_parameters.output_format)
        {   // gpx file
            reply.headers.emplace_back("Content-Type", "application/gpx+xml; charset=UTF-8");
            reply.headers.emplace_back("Content-Disposition", "attachment; filename=\"route.gpx\"");
        }
        else if (route_parameters.jsonp_parameter.empty())
        {   // json file
            reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
            reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.json\"");
        }
        else
        {   // jsonp
            reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
            reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.js\"");
        }
    }
    catch (const std::exception &e)
    {
        reply = http::Reply::StockReply(http::Reply::internalServerError);
        SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
                                         << ", uri: " << req.uri;
        return;
    }
}

void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
<commit_msg>reformat source file Server/RequestHandler.cpp<commit_after>/*

Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#include "APIGrammar.h"
#include "RequestHandler.h"
#include "Http/Request.h"

#include "../DataStructures/JSONContainer.h"
#include "../Library/OSRM.h"
#include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h"
#include "../typedefs.h"

#include <osrm/Reply.h>
#include <osrm/RouteParameters.h>

#include <ctime>

#include <algorithm>
#include <iostream>

RequestHandler::RequestHandler() : routing_machine(nullptr) {}

void RequestHandler::handle_request(const http::Request &req, http::Reply &reply)
{
    // parse command
    try
    {
        std::string request;
        URIDecode(req.uri, request);

        // deactivated as GCC apparently does not implement that, not even in 4.9
        // std::time_t t = std::time(nullptr);
        // SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
        //     " " << req.endpoint.to_string() << " " <<
        //     req.referrer << ( 0 == req.referrer.length() ? "- " :" ") <<
        //     req.agent << ( 0 == req.agent.length() ? "- " :" ") << request;

        time_t ltime;
        struct tm *Tm;

        ltime = time(nullptr);
        Tm = localtime(&ltime);

        // log timestamp
        SimpleLogger().Write() << (Tm->tm_mday < 10 ? "0" : "") << Tm->tm_mday << "-"
                               << (Tm->tm_mon + 1 < 10 ? "0" : "") << (Tm->tm_mon + 1) << "-"
                               << 1900 + Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "")
                               << Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "") << Tm->tm_min
                               << ":" << (Tm->tm_sec < 10 ? "0" : "") << Tm->tm_sec << " "
                               << req.endpoint.to_string() << " " << req.referrer
                               << (0 == req.referrer.length() ? "- " : " ") << req.agent
                               << (0 == req.agent.length() ? "- " : " ") << request;

        RouteParameters route_parameters;
        APIGrammarParser api_parser(&route_parameters);

        auto iter = request.begin();
        const bool result = boost::spirit::qi::parse(iter, request.end(), api_parser);

        // check if the was an error with the request
        if (!result || (iter != request.end()))
        {
            reply = http::Reply::StockReply(http::Reply::badRequest);
            reply.content.clear();
            const unsigned position = static_cast<unsigned>(std::distance(request.begin(), iter));
            JSON::Object json_result;
            json_result.values["status"] = 400;
            std::string message = "Query string malformed close to position ";
            message += UintToString(position);
            json_result.values["status_message"] = message;
            JSON::render(reply.content, json_result);
            return;
        }

        // parsing done, lets call the right plugin to handle the request
        BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");

        if (!route_parameters.jsonp_parameter.empty())
        { // prepend response with jsonp parameter
            const std::string json_p = (route_parameters.jsonp_parameter + "(");
            reply.content.insert(reply.content.end(), json_p.begin(), json_p.end());
        }
        routing_machine->RunQuery(route_parameters, reply);
        if (!route_parameters.jsonp_parameter.empty())
        { // append brace to jsonp response
            reply.content.push_back(')');
        }

        // set headers
        reply.headers.emplace_back("Content-Length",
                                   UintToString(static_cast<unsigned>(reply.content.size())));
        if ("gpx" == route_parameters.output_format)
        { // gpx file
            reply.headers.emplace_back("Content-Type", "application/gpx+xml; charset=UTF-8");
            reply.headers.emplace_back("Content-Disposition", "attachment; filename=\"route.gpx\"");
        }
        else if (route_parameters.jsonp_parameter.empty())
        { // json file
            reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
            reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.json\"");
        }
        else
        { // jsonp
            reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
            reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.js\"");
        }
    }
    catch (const std::exception &e)
    {
        reply = http::Reply::StockReply(http::Reply::internalServerError);
        SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
                                         << ", uri: " << req.uri;
        return;
    }
}

void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
<|endoftext|>