<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "vast/schema.hpp"

#include <utility>

#include <caf/actor_system_config.hpp>

#include "vast/event_types.hpp"
#include "vast/filesystem.hpp"
#include "vast/json.hpp"

#include "vast/concept/parseable/parse.hpp"
#include "vast/concept/parseable/to.hpp"
#include "vast/concept/parseable/vast/schema.hpp"
#include "vast/concept/printable/to_string.hpp"
#include "vast/concept/printable/vast/schema.hpp"
#include "vast/concept/printable/vast/type.hpp"

namespace vast {

optional<schema> schema::merge(const schema& s1, const schema& s2) {
  auto result = s2;
  for (auto& t : s1) {
    if (auto u = s2.find(t.name())) {
      if (t != *u && t.name() == u->name())
        // Type clash: cannot accomodate two types with same name.
        return {};
    } else {
      result.types_.push_back(t);
    }
  }
  return result;
}

schema schema::combine(const schema& s1, const schema& s2) {
  auto result = s1;
  for (auto& t : s2) {
    if (auto x = result.find(t.name()))
      *x = t;
    else
      result.add(t);
  }
  return result;
}

bool schema::add(const type& t) {
  if (caf::holds_alternative<none_type>(t)
      || t.name().empty()
      || find(t.name()))
    return false;
  types_.push_back(std::move(t));
  return true;
}

type* schema::find(std::string_view name) {
  for (auto& t : types_)
    if (t.name() == name)
      return &t;
  return nullptr;
}

const type* schema::find(std::string_view name) const {
  for (auto& t : types_)
    if (t.name() == name)
      return &t;
  return nullptr;
}

schema::const_iterator schema::begin() const {
  return types_.begin();
}

schema::const_iterator schema::end() const {
  return types_.end();
}

size_t schema::size() const {
  return types_.size();
}

bool schema::empty() const {
  return types_.empty();
}

void schema::clear() {
  types_.clear();
}

bool operator==(const schema& x, const schema& y) {
  return x.types_ == y.types_;
}

// TODO: we should figure out a better way to (de)serialize: use manual pointer
// tracking to save types exactly once. Something along those lines:
//
// namespace {
//
// struct pointer_hash {
//  size_t operator()(const type& t) const noexcept {
//    return reinterpret_cast<size_t>(std::launder(t.ptr_.get()));
//  }
//};
//
// using type_cache = std::unordered_set<type, pointer_hash>;
//
// template <class Serializer>
// struct type_serializer {
//
//  type_serializer(Serializer& sink, type_cache& cache)
//    : sink_{sink}, cache_{cache} {
//  }
//
//  void save_type(type const t) const {
//    if (t.name().empty()) {
//      visit(*this, t); // recurse
//      return;
//    }
//    if (cache_.count(t)) {
//      sink_ << t.name();
//      return;
//    }
//    visit(*this, t); // recurse
//    cache_.insert(t.name());
//  }
//
//  template <class T>
//  void operator()(const T& x) const {
//    sink_ << x;
//  };
//
//  void operator()(const vector_type& t) const {
//    save_type(t.value_type);
//  }
//
//  void operator()(const set_type& t) const {
//    save_type(t.value_type);
//  }
//
//  void operator()(const table_type& t) const {
//    save_type(t.key_type);
//    save_type(t.value_type);
//  }
//
//  void operator()(const record_type& t) const {
//    auto size = t.fields.size();
//    sink_.begin_sequence(size);
//    for (auto& f : t.fields) {
//      sink_ << f.name;
//      save_type(f.type);
//    }
//    sink_.end_sequence();
//  }
//
//  Serializer& sink_;
//  type_cache& cache_;
//};
//
//} // namespace <anonymous>

void serialize(caf::serializer& sink, const schema& sch) {
  sink << to_string(sch);
}

void serialize(caf::deserializer& source, schema& sch) {
  std::string str;
  source >> str;
  if (str.empty())
    return;
  sch.clear();
  auto i = str.begin();
  parse(i, str.end(), sch);
}

bool convert(const schema& s, json& j) {
  json::object o;
  json::array a;
  std::transform(s.begin(), s.end(), std::back_inserter(a),
                 [](auto& t) { return to_json(t); });
  o["types"] = std::move(a);
  j = std::move(o);
  return true;
}

caf::expected<schema> load_schema(const path& sf) {
  if (sf.empty())
    return make_error(ec::filesystem_error, "empty path");
  auto str = load_contents(sf);
  if (!str)
    return str.error();
  return to<schema>(*str);
}

caf::expected<schema> load_schema(const std::vector<path>& schema_paths) {
  vast::schema types;
  for (const auto& dir : schema_paths) {
    if (!exists(dir))
      break;
    vast::schema directory_schema;
    for (auto f : directory(dir)) {
      if (f.extension() == ".schema" && exists(f)) {
        switch (f.kind()) {
          default:
            break;
          case path::regular_file:
          case path::symlink: {
            auto schema = load_schema(f);
            if (!schema)
              return schema.error();
            if (auto merged = schema::merge(directory_schema, *schema))
              directory_schema = std::move(*merged);
            else
              return make_error(ec::format_error, "type clash in schema");
          }
        }
      }
    }
    types = schema::combine(types, directory_schema);
  }
  return types;
}

caf::expected<schema> get_schema(const caf::settings& options,
                                 const std::string& category) {
  // Get the default schema from the registry.
  auto schema_reg_ptr = event_types::get();
  auto schema = schema_reg_ptr ? *schema_reg_ptr : vast::schema{};
  // Update with an alternate schema, if requested.
  auto sc = caf::get_if<std::string>(&options, category + ".schema");
  auto sf = caf::get_if<std::string>(&options, category + ".schema-file");
  if (sc && sf)
    make_error(ec::invalid_configuration,
               "had both schema and schema-file provided");
  auto update = [&]() -> caf::expected<vast::schema> {
    if (sc)
      return to<vast::schema>(*sc);
    if (sf)
      return load_schema(*sf);
    return caf::no_error;
  }();
  if (!update) {
    if (update.error() != caf::no_error)
      return make_error(ec::invalid_configuration,
                        "failed to parse provided schema");
    else
      return schema;
  }
  return schema::combine(schema, *update);
}

} // namespace vast
<commit_msg>Move utility include inside updated comment<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "vast/schema.hpp"

#include <caf/actor_system_config.hpp>

#include "vast/event_types.hpp"
#include "vast/filesystem.hpp"
#include "vast/json.hpp"

#include "vast/concept/parseable/parse.hpp"
#include "vast/concept/parseable/to.hpp"
#include "vast/concept/parseable/vast/schema.hpp"
#include "vast/concept/printable/to_string.hpp"
#include "vast/concept/printable/vast/schema.hpp"
#include "vast/concept/printable/vast/type.hpp"

namespace vast {

optional<schema> schema::merge(const schema& s1, const schema& s2) {
  auto result = s2;
  for (auto& t : s1) {
    if (auto u = s2.find(t.name())) {
      if (t != *u && t.name() == u->name())
        // Type clash: cannot accomodate two types with same name.
        return {};
    } else {
      result.types_.push_back(t);
    }
  }
  return result;
}

schema schema::combine(const schema& s1, const schema& s2) {
  auto result = s1;
  for (auto& t : s2) {
    if (auto x = result.find(t.name()))
      *x = t;
    else
      result.add(t);
  }
  return result;
}

bool schema::add(const type& t) {
  if (caf::holds_alternative<none_type>(t)
      || t.name().empty()
      || find(t.name()))
    return false;
  types_.push_back(std::move(t));
  return true;
}

type* schema::find(std::string_view name) {
  for (auto& t : types_)
    if (t.name() == name)
      return &t;
  return nullptr;
}

const type* schema::find(std::string_view name) const {
  for (auto& t : types_)
    if (t.name() == name)
      return &t;
  return nullptr;
}

schema::const_iterator schema::begin() const {
  return types_.begin();
}

schema::const_iterator schema::end() const {
  return types_.end();
}

size_t schema::size() const {
  return types_.size();
}

bool schema::empty() const {
  return types_.empty();
}

void schema::clear() {
  types_.clear();
}

bool operator==(const schema& x, const schema& y) {
  return x.types_ == y.types_;
}

// TODO: we should figure out a better way to (de)serialize: use manual pointer
// tracking to save types exactly once. Something along those lines:
//
// #include <utility>
//
// namespace {
//
// struct pointer_hash {
//  size_t operator()(const type& t) const noexcept {
//    return reinterpret_cast<size_t>(std::launder(t.ptr_.get()));
//  }
//};
//
// using type_cache = std::unordered_set<type, pointer_hash>;
//
// template <class Serializer>
// struct type_serializer {
//
//  type_serializer(Serializer& sink, type_cache& cache)
//    : sink_{sink}, cache_{cache} {
//  }
//
//  void save_type(type const t) const {
//    if (t.name().empty()) {
//      visit(*this, t); // recurse
//      return;
//    }
//    if (cache_.count(t)) {
//      sink_ << t.name();
//      return;
//    }
//    visit(*this, t); // recurse
//    cache_.insert(t.name());
//  }
//
//  template <class T>
//  void operator()(const T& x) const {
//    sink_ << x;
//  };
//
//  void operator()(const vector_type& t) const {
//    save_type(t.value_type);
//  }
//
//  void operator()(const set_type& t) const {
//    save_type(t.value_type);
//  }
//
//  void operator()(const table_type& t) const {
//    save_type(t.key_type);
//    save_type(t.value_type);
//  }
//
//  void operator()(const record_type& t) const {
//    auto size = t.fields.size();
//    sink_.begin_sequence(size);
//    for (auto& f : t.fields) {
//      sink_ << f.name;
//      save_type(f.type);
//    }
//    sink_.end_sequence();
//  }
//
//  Serializer& sink_;
//  type_cache& cache_;
//};
//
//} // namespace <anonymous>

void serialize(caf::serializer& sink, const schema& sch) {
  sink << to_string(sch);
}

void serialize(caf::deserializer& source, schema& sch) {
  std::string str;
  source >> str;
  if (str.empty())
    return;
  sch.clear();
  auto i = str.begin();
  parse(i, str.end(), sch);
}

bool convert(const schema& s, json& j) {
  json::object o;
  json::array a;
  std::transform(s.begin(), s.end(), std::back_inserter(a),
                 [](auto& t) { return to_json(t); });
  o["types"] = std::move(a);
  j = std::move(o);
  return true;
}

caf::expected<schema> load_schema(const path& sf) {
  if (sf.empty())
    return make_error(ec::filesystem_error, "empty path");
  auto str = load_contents(sf);
  if (!str)
    return str.error();
  return to<schema>(*str);
}

caf::expected<schema> load_schema(const std::vector<path>& schema_paths) {
  vast::schema types;
  for (const auto& dir : schema_paths) {
    if (!exists(dir))
      break;
    vast::schema directory_schema;
    for (auto f : directory(dir)) {
      if (f.extension() == ".schema" && exists(f)) {
        switch (f.kind()) {
          default:
            break;
          case path::regular_file:
          case path::symlink: {
            auto schema = load_schema(f);
            if (!schema)
              return schema.error();
            if (auto merged = schema::merge(directory_schema, *schema))
              directory_schema = std::move(*merged);
            else
              return make_error(ec::format_error, "type clash in schema");
          }
        }
      }
    }
    types = schema::combine(types, directory_schema);
  }
  return types;
}

caf::expected<schema> get_schema(const caf::settings& options,
                                 const std::string& category) {
  // Get the default schema from the registry.
  auto schema_reg_ptr = event_types::get();
  auto schema = schema_reg_ptr ? *schema_reg_ptr : vast::schema{};
  // Update with an alternate schema, if requested.
  auto sc = caf::get_if<std::string>(&options, category + ".schema");
  auto sf = caf::get_if<std::string>(&options, category + ".schema-file");
  if (sc && sf)
    make_error(ec::invalid_configuration,
               "had both schema and schema-file provided");
  auto update = [&]() -> caf::expected<vast::schema> {
    if (sc)
      return to<vast::schema>(*sc);
    if (sf)
      return load_schema(*sf);
    return caf::no_error;
  }();
  if (!update) {
    if (update.error() != caf::no_error)
      return make_error(ec::invalid_configuration,
                        "failed to parse provided schema");
    else
      return schema;
  }
  return schema::combine(schema, *update);
}

} // namespace vast
<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 Steinwurf ApS
// 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.
//     * Neither the name of Steinwurf ApS nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// 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 Steinwurf ApS 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.

#pragma once

namespace sak
{
    /// Ceiling for integer division - ceil(numerator/denominator)
    /// @param numerator the division numerator
    /// @param denominator the division denominator
    /// @return returns the ceiled result of integer division
    inline uint32_t ceil_division(uint32_t numerator, uint32_t denominator)
    {
        assert(denominator > 0);

        if (numerator == 0)
            return 0;

        return ((numerator - 1) / denominator) + 1;
    }
}
<commit_msg>Added missing include<commit_after>// Copyright (c) 2011-2013 Steinwurf ApS
// 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.
//     * Neither the name of Steinwurf ApS nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// 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 Steinwurf ApS 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.

#pragma once

#include <cstdint>

namespace sak
{
    /// Ceiling for integer division - ceil(numerator/denominator)
    /// @param numerator the division numerator
    /// @param denominator the division denominator
    /// @return returns the ceiled result of integer division
    inline uint32_t ceil_division(uint32_t numerator, uint32_t denominator)
    {
        assert(denominator > 0);

        if (numerator == 0)
            return 0;

        return ((numerator - 1) / denominator) + 1;
    }
}
<|endoftext|>


<commit_before>// test_CryptorPK.cpp -- Test Sodium::CryptorPK
//
// Copyright (C) 2017 Farid Hajji <farid@hajji.name>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Sodium::CryptorPK Test
#include <boost/test/included/unit_test.hpp>

#include <sodium.h>
#include "cryptorpk.h"
#include "key.h"
#include "keypair.h"
#include "nonce.h"
#include <string>

using Sodium::Key;
using Sodium::KeyPair;
using Sodium::Nonce;
using Sodium::CryptorPK;
using data_t = Sodium::data_t;

bool
test_of_correctness(const std::string &plaintext)
{
  CryptorPK               sc            {};
  KeyPair                 keypair_alice {};
  KeyPair                 keypair_bob   {};
  Nonce<CryptorPK::NSZPK> nonce         {};

  data_t plainblob {plaintext.cbegin(), plaintext.cend()};

  // 1. alice gets the public key from bob, and sends him a message

  data_t ciphertext_from_alice_to_bob =
    sc.encrypt(plainblob,
	       keypair_bob.pubkey(),
	       keypair_alice.privkey(),
	       nonce);

  // 2. bob gets the public key from alice, and decrypts the message

  data_t decrypted_by_bob_from_alice =
    sc.decrypt(ciphertext_from_alice_to_bob,
	       keypair_bob.privkey(),
	       keypair_alice.pubkey(),
	       nonce);

  // 3. if decryption (MAC or signature) fails, decrypt() would throw,
  // but we manually check anyway.

  BOOST_CHECK(plainblob == decrypted_by_bob_from_alice);

  // 4. bob echoes the messages back to alice. Remember to increment nonce!

  nonce.increment(); // IMPORTANT! before calling encrypt() again

  data_t ciphertext_from_bob_to_alice =
    sc.encrypt(decrypted_by_bob_from_alice,
	       keypair_alice.pubkey(),
	       keypair_bob.privkey(),
	       nonce);

  // 5. alice attempts to decrypt again (also with the incremented nonce)
  data_t decrypted_by_alice_from_bob =
    sc.decrypt(ciphertext_from_bob_to_alice,
	       keypair_alice.privkey(),
	       keypair_bob.pubkey(),
	       nonce);

  // 6. if decryption (MAC or signature) fails, decrypt() would throw,
  // but we manually check anyway. We assume that bob echoed the
  // plaintext without modifying it.

  BOOST_CHECK(plainblob == decrypted_by_alice_from_bob);

  return plainblob == decrypted_by_alice_from_bob;
}

struct SodiumFixture {
  SodiumFixture()  {
    BOOST_REQUIRE(sodium_init() != -1);
    BOOST_TEST_MESSAGE("SodiumFixture(): sodium_init() successful.");
  }
  ~SodiumFixture() {
    BOOST_TEST_MESSAGE("~SodiumFixture(): teardown -- no-op.");
  }
};

BOOST_FIXTURE_TEST_SUITE ( sodium_test_suite, SodiumFixture );

BOOST_AUTO_TEST_CASE( sodium_cryptorpk_test_full_plaintext )
{
  std::string plaintext {"the quick brown fox jumps over the lazy dog"};
  BOOST_CHECK(test_of_correctness(plaintext));
}

BOOST_AUTO_TEST_CASE( sodium_cryptorpk_test_empty_plaintext )
{
  std::string plaintext {};
  BOOST_CHECK(test_of_correctness(plaintext));
}

BOOST_AUTO_TEST_SUITE_END ();
<commit_msg>Added unit tests to Sodium::CryptorPK.<commit_after>// test_CryptorPK.cpp -- Test Sodium::CryptorPK
//
// Copyright (C) 2017 Farid Hajji <farid@hajji.name>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Sodium::CryptorPK Test
#include <boost/test/included/unit_test.hpp>

#include <sodium.h>
#include "cryptorpk.h"
#include "keypair.h"
#include "nonce.h"
#include <string>

using Sodium::KeyPair;
using Sodium::Nonce;
using Sodium::CryptorPK;
using data_t = Sodium::data_t;

bool
test_of_correctness(const std::string &plaintext)
{
  CryptorPK               sc            {};
  KeyPair                 keypair_alice {};
  KeyPair                 keypair_bob   {};
  Nonce<CryptorPK::NSZPK> nonce         {};

  data_t plainblob {plaintext.cbegin(), plaintext.cend()};

  // 1. alice gets the public key from bob, and sends him a message

  data_t ciphertext_from_alice_to_bob =
    sc.encrypt(plainblob,
	       keypair_bob.pubkey(),
	       keypair_alice.privkey(),
	       nonce);

  // 2. bob gets the public key from alice, and decrypts the message

  data_t decrypted_by_bob_from_alice =
    sc.decrypt(ciphertext_from_alice_to_bob,
	       keypair_bob.privkey(),
	       keypair_alice.pubkey(),
	       nonce);

  // 3. if decryption (MAC or signature) fails, decrypt() would throw,
  // but we manually check anyway.

  BOOST_CHECK(plainblob == decrypted_by_bob_from_alice);

  // 4. bob echoes the messages back to alice. Remember to increment nonce!

  nonce.increment(); // IMPORTANT! before calling encrypt() again

  data_t ciphertext_from_bob_to_alice =
    sc.encrypt(decrypted_by_bob_from_alice,
	       keypair_alice.pubkey(),
	       keypair_bob.privkey(),
	       nonce);

  // 5. alice attempts to decrypt again (also with the incremented nonce)
  data_t decrypted_by_alice_from_bob =
    sc.decrypt(ciphertext_from_bob_to_alice,
	       keypair_alice.privkey(),
	       keypair_bob.pubkey(),
	       nonce);

  // 6. if decryption (MAC or signature) fails, decrypt() would throw,
  // but we manually check anyway. We assume that bob echoed the
  // plaintext without modifying it.

  BOOST_CHECK(plainblob == decrypted_by_alice_from_bob);

  return plainblob == decrypted_by_alice_from_bob;
}

bool
falsify_mac(const std::string &plaintext)
{
  CryptorPK               sc            {};
  KeyPair                 keypair_alice {};
  Nonce<CryptorPK::NSZPK> nonce         {};

  data_t plainblob {plaintext.cbegin(), plaintext.cend()};

  data_t ciphertext = sc.encrypt(plainblob,
				 keypair_alice,
				 nonce);

  BOOST_CHECK(ciphertext.size() >= CryptorPK::MACSIZE);

  // falsify mac, which starts before the ciphertext proper
  ++ciphertext[0];

  try {
    data_t decrypted = sc.decrypt(ciphertext,
				  keypair_alice,
				  nonce);
  }
  catch (std::exception &e) {
    // decryption failed as expected: test passed.
    return true;
  }

  // No expection caught: decryption went ahead, eventhough we've
  // modified the mac. Test failed.

  return false;
}

bool
falsify_ciphertext(const std::string &plaintext)
{
  // before even bothering falsifying a ciphertext, check that the
  // corresponding plaintext is not emptry!
  BOOST_CHECK_MESSAGE(! plaintext.empty(),
		      "Nothing to falsify, empty plaintext");

  CryptorPK               sc            {};
  KeyPair                 keypair_alice {};
  Nonce<CryptorPK::NSZPK> nonce         {};

  data_t plainblob {plaintext.cbegin(), plaintext.cend()};

  // encrypt to self
  data_t ciphertext = sc.encrypt(plainblob,
				 keypair_alice,
				 nonce);

  BOOST_CHECK(ciphertext.size() > CryptorPK::MACSIZE);

  // falsify ciphertext, which starts just after MAC
  ++ciphertext[CryptorPK::MACSIZE];

  try {
    data_t decrypted = sc.decrypt(ciphertext,
				  keypair_alice,
				  nonce);
  }
  catch (std::exception &e) {
    // Exception caught as expected. Test passed.
    return true;
  }

  // Expection not caught: decryption went ahead, eventhough we've
  // modified the ciphertext. Test failed.

  return false;
}

struct SodiumFixture {
  SodiumFixture()  {
    BOOST_REQUIRE(sodium_init() != -1);
    BOOST_TEST_MESSAGE("SodiumFixture(): sodium_init() successful.");
  }
  ~SodiumFixture() {
    BOOST_TEST_MESSAGE("~SodiumFixture(): teardown -- no-op.");
  }
};

BOOST_FIXTURE_TEST_SUITE ( sodium_test_suite, SodiumFixture );

BOOST_AUTO_TEST_CASE( sodium_cryptorpk_test_full_plaintext )
{
  std::string plaintext {"the quick brown fox jumps over the lazy dog"};
  BOOST_CHECK(test_of_correctness(plaintext));
}

BOOST_AUTO_TEST_CASE( sodium_cryptorpk_test_empty_plaintext )
{
  std::string plaintext {};
  BOOST_CHECK(test_of_correctness(plaintext));
}

BOOST_AUTO_TEST_CASE( sodium_cryptopk_test_encrypt_to_self )
{
  CryptorPK               sc            {};
  KeyPair                 keypair_alice {};
  Nonce<CryptorPK::NSZPK> nonce         {};

  std::string plaintext {"the quick brown fox jumps over the lazy dog"};
  data_t plainblob {plaintext.cbegin(), plaintext.cend()};

  data_t ciphertext = sc.encrypt(plainblob,
				 keypair_alice,
				 nonce);

  BOOST_CHECK_EQUAL(ciphertext.size(), plainblob.size() + CryptorPK::MACSIZE);

  data_t decrypted = sc.decrypt(ciphertext,
				keypair_alice,
				nonce);

  // if the ciphertext (with MAC) was modified, or came from another
  // source, decryption would have thrown. But we manually check anyway.

  BOOST_CHECK(plainblob == decrypted);
}

BOOST_AUTO_TEST_CASE( sodium_cryptopk_test_falsify_ciphertext )
{
  std::string plaintext {"the quick brown fox jumps over the lazy dog"};

  BOOST_CHECK(falsify_ciphertext(plaintext));
}

BOOST_AUTO_TEST_CASE( sodium_cryptopk_test_falsify_mac_fulltext )
{
  std::string plaintext {"the quick brown fox jumps over the lazy dog"};

  BOOST_CHECK(falsify_mac(plaintext));
}

BOOST_AUTO_TEST_CASE( sodium_cryptopk_test_falsify_mac_empty )
{
  std::string plaintext {};

  BOOST_CHECK(falsify_mac(plaintext));
}

BOOST_AUTO_TEST_SUITE_END ();
<|endoftext|>


<commit_before>#include "BinaryTree.hpp"
#include <catch.hpp>

SCENARIO("default constructor")
{
	Tree<int> node;
	REQUIRE(node.root_() == nullptr);
}

SCENARIO("insert")
{
	Tree<int> tree;
	tree.insert(7);
	REQUIRE(tree.x_() == 7);
	REQUIRE(tree.left_() == nullptr);
	REQUIRE(tree.right_() == nullptr);
}

SCENARIO("search")
{
	Tree<int> tree;
	bool a;
	tree.insert(7);
	a = tree.check_search(7);
	REQUIRE(a == true);
}

SCENARIO("size")
{
	Tree<int> tree;
	int size = 0;
	tree.insert(7);
	size = tree.size(tree.root_());
	REQUIRE(size == 1);
}

SCENARIO("deleteX")
{
	Tree<int> tree;
	int size1, size2;
	tree.insert(3);
	tree.insert(4);
	tree.insert(2);
	tree.insert(0);
	size1 = tree.size(tree.root_());
	tree.deleteX(0);
	size2 = tree.size(tree.root_());
	REQUIRE(size1 == 1 + size2);
}

SCENARIO("out_to_file", "fIn")
{
	Tree<int> tree1, tree2;
	int size1, size2;
	tree1.insert(3);
	tree1.insert(4);
	tree1.out_to_file("TreeOut.txt");
	size1 = tree1.size(tree1.root_());
	tree2.fIn("TreeOut.txt");
	size2 = tree2.size(tree2.root_());
	REQUIRE(size1 == 2);
	REQUIRE(size2 == 2);
	REQUIRE(tree2.x_() == 3);
	REQUIRE(tree2.left_() == nullptr);
	REQUIRE(tree2.right_() != nullptr);
}
<commit_msg>Update init.cpp<commit_after>#include "BinaryTree.hpp"
#include <catch.hpp>

SCENARIO("default constructor")
{
	Tree<int> node;
	REQUIRE(node.root_() == nullptr);
}

SCENARIO("insert")
{
	Tree<int> tree;
	tree.insert(7);
	REQUIRE(tree.x_() == 7);
	REQUIRE(tree.left_() == nullptr);
	REQUIRE(tree.right_() == nullptr);
}

SCENARIO("search")
{
	Tree<int> tree;
	bool a;
	tree.insert(7);
	a = tree.check_search(7);
	REQUIRE(a == true);
}

SCENARIO("size")
{
	Tree<int> tree;
	int size = 0;
	tree.insert(7);
	size = tree.size(tree.root_());
	REQUIRE(size == 1);
}

SCENARIO("prev_")
{
	Tree<int> tree;
	Node<int> * node;
	tree.insert(3);
	tree.insert(4);
	tree.insert(2);
	node = tree.prev_(4);
	REQUIRE(node->x == x_());
}

SCENARIO("deleteX")
{
	Tree<int> tree;
	int size1, size2;
	tree.insert(3);
	tree.insert(4);
	tree.insert(2);
	tree.insert(0);
	size1 = tree.size(tree.root_());
	tree.deleteX(0);
	size2 = tree.size(tree.root_());
	REQUIRE(size1 == 1 + size2);
}

SCENARIO("out_to_file", "fIn")
{
	Tree<int> tree1, tree2;
	int size1, size2;
	tree1.insert(3);
	tree1.insert(4);
	tree1.out_to_file("TreeOut.txt");
	size1 = tree1.size(tree1.root_());
	tree2.fIn("TreeOut.txt");
	size2 = tree2.size(tree2.root_());
	REQUIRE(size1 == 2);
	REQUIRE(size2 == 2);
	REQUIRE(tree2.x_() == 3);
	REQUIRE(tree2.left_() == nullptr);
	REQUIRE(tree2.right_() != nullptr);
}
<|endoftext|>


<commit_before>#define CATCH_CONFIG_RUNNER
#include <catch.hpp>
// #include <glm/glm.hpp>
// #include <glm/gtx/intersect.hpp>
#include "shape.hpp"
#include "sphere.hpp"
#include "box.hpp"
#include "material.hpp"
#include "lights.hpp"
#include "camera.hpp"

TEST_CASE("test material", "[test material]")
{
    std::cout << std::endl << "Material Tests:" << std::endl;

    std::cout << "(Default-Konstructor)" <<std::endl;
    Material mat1;
    std::string s1 = "noname";
    Color col1{};
    REQUIRE(mat1.name() == s1);
    REQUIRE(mat1.ka() == col1);
    REQUIRE(mat1.kd() == col1);
    REQUIRE(mat1.ks() == col1);
    REQUIRE(mat1.m() == 0);
    std::cout << mat1;

    std::cout << std::endl << "(Konstructor)" << std::endl;
    std::string s2 = "mat2";
    Color col2{1.0f,0.0f,1.0f};
    Material mat2{s2,col2,col2,col2,1};
    REQUIRE(mat2.name() == s2);
    REQUIRE(mat2.ka() == col2);
    REQUIRE(mat2.kd() == col2);
    REQUIRE(mat2.ks() == col2);
    REQUIRE(mat2.m() == 1);
    std::cout << mat2;
}

TEST_CASE("test box", "[test box]")
{
    std::cout << std::endl << "Box Tests:" << std::endl;

    Box box1;
    glm::vec3 vec3{};
    REQUIRE(box1.min() == vec3);
    REQUIRE(box1.max() == vec3);

    Box box2{glm::vec3{1.0,1.0,1.0},glm::vec3{3.0,4.0,5.0}};
    glm::vec3 p1{1.0,1.0,1.0};
    glm::vec3 p2{3.0,4.0,5.0};
    REQUIRE(box2.min() == p1);
    REQUIRE(box2.max() == p2);
    REQUIRE(box2.area() == Approx(52.0));
    REQUIRE(box2.volume() == Approx(24.0));

    std::cout << std::endl;
    std::string b = "Box3";
    Material mat{};
    Box box3{glm::vec3{1.0,1.0,1.0}, glm::vec3{2.0,2.0,2.0}, b, mat};
    REQUIRE(box3.name() == b);
    REQUIRE(box3.material() == mat);
    std::cout << box3;
}

TEST_CASE("test sphere", "[test sphere]")
{
    std::cout << std::endl << "Sphere Tests:" << std::endl;

    Sphere sphere0;
    glm::vec3 vec0{};
    std::string a = "noname";
    Material mat{};
    REQUIRE(sphere0.radius() == Approx(0.0));
    REQUIRE(sphere0.center() == vec0);
    REQUIRE(sphere0.name() == a);
    REQUIRE(sphere0.material() == mat);
    std::cout << sphere0;

    glm::vec3 vec1{1.0,1.0,1.0};
    std::string b = "sphere1";
    Sphere sphere1{vec1, 1.0, b, mat};
    REQUIRE(sphere1.radius() == Approx(1.0));
    REQUIRE(sphere1.center() == vec1);
    REQUIRE(sphere1.name() == b);
    REQUIRE(sphere1.material() == mat);
    REQUIRE(sphere1.area() == Approx(12.5664));
    REQUIRE(sphere1.volume() == Approx(4.18879f));
    std::cout << sphere1;
}

TEST_CASE("intersectRaySphere", "[intersectRaySphere]")
{
    std::cout << std::endl << "intersect Ray-Sphere:" << std::endl;

    glm::vec3 ray_origin1(0.0,0.0,0.0);
    glm::vec3 ray_direction1(0.0,0.0,1.0);
    Ray ray1{ray_origin1,ray_direction1};

    glm::vec3 ray_origin2(2.0,1.0,3.0);
    glm::vec3 ray_direction2(4.0,2.0,6.0);
    Ray ray2{ray_origin2,ray_direction2};

    float sphere_radius(1.0);
    Material mat{};
    glm::vec3 sphere_center0(0.0,0.0,5.0);
    std::string a = "sphere0";
    Sphere sphere0{sphere_center0, sphere_radius, a, mat};

    glm::vec3 sphere_center1(3.0,1.5,4.5);
    std::string b = "sphere1";
    Sphere sphere1{sphere_center1, sphere_radius, b, mat};

    glm::vec3 sphere_center2(7.0,7.0,7.0);
    std::string c = "sphere2";
    Sphere sphere2{sphere_center2, sphere_radius, c, mat};

    float distance(0.0);
    REQUIRE(sphere0.intersect(ray1, distance) == true);
    REQUIRE(distance == Approx(4.0f));
    REQUIRE(sphere1.intersect(ray2, distance) == true);
    REQUIRE(sphere2.intersect(ray2, distance) == false);
}

TEST_CASE("intersectRayBox", "[intersectRayBox]")
{
    std::cout << std::endl << "intersect Ray-Box:" << std::endl;

    glm::vec3 ray_origin1(0.0,0.0,0.0);
    glm::vec3 ray_direction1(1.0,1.0,1.0);
    Ray ray1{ray_origin1,ray_direction1};

    glm::vec3 ray_origin2(3.0,1.5,4.5);
    glm::vec3 ray_direction2(-1.0,-1.0,-1.0);
    Ray ray2{ray_origin2,ray_direction2};

    std::string a = "box0";
    Material mat{};
    glm::vec3 box_min0(2.0,2.0,2.0);
    glm::vec3 box_max0(4.0,4.0,4.0);
    Box box0{box_min0, box_max0, a, mat};

    std::string b = "box1";
    glm::vec3 box_min1(3.0,1.5,4.5);
    glm::vec3 box_max1(1.0,1.0,1.0);
    Box box1{box_min1, box_max1, b, mat};

    std::string c = "box2";
    glm::vec3 box_min2(7.0,7.0,7.0);
    glm::vec3 box_max2(6.0,8.0,6.0);
    Box box2{box_min2, box_max2, c, mat};

    float distance(0.0);
    REQUIRE(box0.intersect(ray1, distance) == true);
    REQUIRE(box1.intersect(ray2, distance) == true);
    REQUIRE(box2.intersect(ray2, distance) == false);
}

TEST_CASE("Lights_default", "[Lights_default]"){

    std::cout << std::endl << "Tests Lights:" << std::endl;

    Light l1;
    std::string s1 = "noname";
    glm::vec3 pos0(0.0,0.0,0.0);
    Color c0;
    REQUIRE(l1.name() == s1);
    REQUIRE(l1.pos() == pos0);
    REQUIRE(l1.dl() == c0);
}

TEST_CASE("Camera_default", "[Camera_default]"){

    std::cout << std::endl << "Tests Camera:" << std::endl;

    Camera c1;
    std::string s1 = "defaultcam";
    glm::vec3 pos0(0.0,0.0,0.0);
    float fovx = 60.0f;
    REQUIRE(c1.name() == s1);
    REQUIRE(c1.pos() == pos0);
    REQUIRE(c1.fovx() == fovx);
}

// AUFGABENBLATT 6
/*TEST_CASE("statischer Typ/dynamischer Typ Variable", "[6.7]")
{
    std::cout << std::endl << "6.7:" << std::endl;

    Color  rot(255,0,0);
    Material red("ton" ,rot,rot,rot,7.1f);
    glm::vec3 position(0,0,0);

    std::shared_ptr<Sphere> s1 = std::make_shared<Sphere>(
        position, 1.2, "sphere0", red
    );

    std::shared_ptr<Shape> s2 = std::make_shared<Sphere>(
        position, 1.2, "sphere1", red
    );

    s1->print(std::cout);
    s2->print(std::cout);

    //C++ ist eine statisch typisierte Sprache.
    //In C++ können Variablen einer Basisklasse Objekte einer abgeleiteten Klasse referenzieren.
    //Da hier im Beispiel die Pointer von verschiedenen Typen sind, kann man sehen, dass diese trotzdem auf das gleiche Objekt zeigen können.
    //Der erste erzeugte Sphere-Pointer zeigt auf eine Sphere, hier sind statische und dynamische Klasse die selbe.
    //Der zweite erzeugte Shape-Pointer zeigt auf eine Sphere, hier ist Shape die statische und Sphere ist die dynamische Klasse.
}

TEST_CASE("destructor", "[6.8]")
{
    std::cout << std::endl << "6.8:" << std::endl;

    Material red("red",Color {255,0,0}, 0.0);
    glm::vec3 position(0,0,0);

    Sphere* s1 = new Sphere(position, 1.2f, "sphere0", red);
    Shape* s2 = new Sphere(position, 1.2f, "sphere1", red);

    s1->print(std::cout);
    s2->print(std::cout);

    delete s1;
    delete s2;

    //Ohne virtual wird beim Shape-Pointer der Destruktor der Sphere nicht aufgerufen, da hier nur der Destruktor von der Klasse aufgerufen wird auf den der Pointer zeigt.
    //Bei dem Sphere-Pointer werden zwei Destruktoren aufgerufen, da wenn der Destruktor der Sphere aufgerufen wird, auf welche der Pointer zeigt, automatisch auch noch der Destruktor der Basisklasse aufgerufen wird.
    //Wenn man virtual verwendet wird auch für den Shape-Pointer der Destruktor der Sphere-Klasse aufgerufen, da der Destruktor des Pointers virtual und Sphere die abgeleitete Klasse der Basisklasse Shape ist.
}*/

int main(int argc, char *argv[])
{
  return Catch::Session().run(argc, argv);
}
<commit_msg>default strings fix<commit_after>#define CATCH_CONFIG_RUNNER
#include <catch.hpp>
// #include <glm/glm.hpp>
// #include <glm/gtx/intersect.hpp>
#include "shape.hpp"
#include "sphere.hpp"
#include "box.hpp"
#include "material.hpp"
#include "lights.hpp"
#include "camera.hpp"

TEST_CASE("test material", "[test material]")
{
    std::cout << std::endl << "Material Tests:" << std::endl;

    std::cout << "(Default-Konstructor)" <<std::endl;
    Material mat1;
    std::string s1 = "defaultmaterial";
    Color col1{};
    REQUIRE(mat1.name() == s1);
    REQUIRE(mat1.ka() == col1);
    REQUIRE(mat1.kd() == col1);
    REQUIRE(mat1.ks() == col1);
    REQUIRE(mat1.m() == 0);
    std::cout << mat1;

    std::cout << std::endl << "(Konstructor)" << std::endl;
    std::string s2 = "mat2";
    Color col2{1.0f,0.0f,1.0f};
    Material mat2{s2,col2,col2,col2,1};
    REQUIRE(mat2.name() == s2);
    REQUIRE(mat2.ka() == col2);
    REQUIRE(mat2.kd() == col2);
    REQUIRE(mat2.ks() == col2);
    REQUIRE(mat2.m() == 1);
    std::cout << mat2;
}

TEST_CASE("test box", "[test box]")
{
    std::cout << std::endl << "Box Tests:" << std::endl;

    Box box1;
    glm::vec3 vec3{};
    REQUIRE(box1.min() == vec3);
    REQUIRE(box1.max() == vec3);

    Box box2{glm::vec3{1.0,1.0,1.0},glm::vec3{3.0,4.0,5.0}};
    glm::vec3 p1{1.0,1.0,1.0};
    glm::vec3 p2{3.0,4.0,5.0};
    REQUIRE(box2.min() == p1);
    REQUIRE(box2.max() == p2);
    REQUIRE(box2.area() == Approx(52.0));
    REQUIRE(box2.volume() == Approx(24.0));

    std::cout << std::endl;
    std::string b = "Box3";
    Material mat{};
    Box box3{glm::vec3{1.0,1.0,1.0}, glm::vec3{2.0,2.0,2.0}, b, mat};
    REQUIRE(box3.name() == b);
    REQUIRE(box3.material() == mat);
    std::cout << box3;
}

TEST_CASE("test sphere", "[test sphere]")
{
    std::cout << std::endl << "Sphere Tests:" << std::endl;

    Sphere sphere0;
    glm::vec3 vec0{};
    std::string a = "defaultshape";
    Material mat{};
    REQUIRE(sphere0.radius() == Approx(0.0));
    REQUIRE(sphere0.center() == vec0);
    REQUIRE(sphere0.name() == a);
    REQUIRE(sphere0.material() == mat);
    std::cout << sphere0;

    glm::vec3 vec1{1.0,1.0,1.0};
    std::string b = "sphere1";
    Sphere sphere1{vec1, 1.0, b, mat};
    REQUIRE(sphere1.radius() == Approx(1.0));
    REQUIRE(sphere1.center() == vec1);
    REQUIRE(sphere1.name() == b);
    REQUIRE(sphere1.material() == mat);
    REQUIRE(sphere1.area() == Approx(12.5664));
    REQUIRE(sphere1.volume() == Approx(4.18879f));
    std::cout << sphere1;
}

TEST_CASE("intersectRaySphere", "[intersectRaySphere]")
{
    std::cout << std::endl << "intersect Ray-Sphere:" << std::endl;

    glm::vec3 ray_origin1(0.0,0.0,0.0);
    glm::vec3 ray_direction1(0.0,0.0,1.0);
    Ray ray1{ray_origin1,ray_direction1};

    glm::vec3 ray_origin2(2.0,1.0,3.0);
    glm::vec3 ray_direction2(4.0,2.0,6.0);
    Ray ray2{ray_origin2,ray_direction2};

    float sphere_radius(1.0);
    Material mat{};
    glm::vec3 sphere_center0(0.0,0.0,5.0);
    std::string a = "sphere0";
    Sphere sphere0{sphere_center0, sphere_radius, a, mat};

    glm::vec3 sphere_center1(3.0,1.5,4.5);
    std::string b = "sphere1";
    Sphere sphere1{sphere_center1, sphere_radius, b, mat};

    glm::vec3 sphere_center2(7.0,7.0,7.0);
    std::string c = "sphere2";
    Sphere sphere2{sphere_center2, sphere_radius, c, mat};

    float distance(0.0);
    REQUIRE(sphere0.intersect(ray1, distance) == true);
    REQUIRE(distance == Approx(4.0f));
    REQUIRE(sphere1.intersect(ray2, distance) == true);
    REQUIRE(sphere2.intersect(ray2, distance) == false);
}

TEST_CASE("intersectRayBox", "[intersectRayBox]")
{
    std::cout << std::endl << "intersect Ray-Box:" << std::endl;

    glm::vec3 ray_origin1(0.0,0.0,0.0);
    glm::vec3 ray_direction1(1.0,1.0,1.0);
    Ray ray1{ray_origin1,ray_direction1};

    glm::vec3 ray_origin2(3.0,1.5,4.5);
    glm::vec3 ray_direction2(-1.0,-1.0,-1.0);
    Ray ray2{ray_origin2,ray_direction2};

    std::string a = "box0";
    Material mat{};
    glm::vec3 box_min0(2.0,2.0,2.0);
    glm::vec3 box_max0(4.0,4.0,4.0);
    Box box0{box_min0, box_max0, a, mat};

    std::string b = "box1";
    glm::vec3 box_min1(3.0,1.5,4.5);
    glm::vec3 box_max1(1.0,1.0,1.0);
    Box box1{box_min1, box_max1, b, mat};

    std::string c = "box2";
    glm::vec3 box_min2(7.0,7.0,7.0);
    glm::vec3 box_max2(6.0,8.0,6.0);
    Box box2{box_min2, box_max2, c, mat};

    float distance(0.0);
    REQUIRE(box0.intersect(ray1, distance) == true);
    REQUIRE(box1.intersect(ray2, distance) == true);
    REQUIRE(box2.intersect(ray2, distance) == false);
}

TEST_CASE("Lights_default", "[Lights_default]"){

    std::cout << std::endl << "Tests Lights:" << std::endl;

    Light l1;
    std::string s1 = "defaultlight";
    glm::vec3 pos0(0.0,0.0,0.0);
    Color c0;
    REQUIRE(l1.name() == s1);
    REQUIRE(l1.pos() == pos0);
    REQUIRE(l1.dl() == c0);
}

TEST_CASE("Camera_default", "[Camera_default]"){

    std::cout << std::endl << "Tests Camera:" << std::endl;

    Camera c1;
    std::string s1 = "defaultcam";
    glm::vec3 pos0(0.0,0.0,0.0);
    float fovx = 60.0f;
    REQUIRE(c1.name() == s1);
    REQUIRE(c1.pos() == pos0);
    REQUIRE(c1.fovx() == fovx);
}

// AUFGABENBLATT 6
/*TEST_CASE("statischer Typ/dynamischer Typ Variable", "[6.7]")
{
    std::cout << std::endl << "6.7:" << std::endl;

    Color  rot(255,0,0);
    Material red("ton" ,rot,rot,rot,7.1f);
    glm::vec3 position(0,0,0);

    std::shared_ptr<Sphere> s1 = std::make_shared<Sphere>(
        position, 1.2, "sphere0", red
    );

    std::shared_ptr<Shape> s2 = std::make_shared<Sphere>(
        position, 1.2, "sphere1", red
    );

    s1->print(std::cout);
    s2->print(std::cout);

    //C++ ist eine statisch typisierte Sprache.
    //In C++ können Variablen einer Basisklasse Objekte einer abgeleiteten Klasse referenzieren.
    //Da hier im Beispiel die Pointer von verschiedenen Typen sind, kann man sehen, dass diese trotzdem auf das gleiche Objekt zeigen können.
    //Der erste erzeugte Sphere-Pointer zeigt auf eine Sphere, hier sind statische und dynamische Klasse die selbe.
    //Der zweite erzeugte Shape-Pointer zeigt auf eine Sphere, hier ist Shape die statische und Sphere ist die dynamische Klasse.
}

TEST_CASE("destructor", "[6.8]")
{
    std::cout << std::endl << "6.8:" << std::endl;

    Material red("red",Color {255,0,0}, 0.0);
    glm::vec3 position(0,0,0);

    Sphere* s1 = new Sphere(position, 1.2f, "sphere0", red);
    Shape* s2 = new Sphere(position, 1.2f, "sphere1", red);

    s1->print(std::cout);
    s2->print(std::cout);

    delete s1;
    delete s2;

    //Ohne virtual wird beim Shape-Pointer der Destruktor der Sphere nicht aufgerufen, da hier nur der Destruktor von der Klasse aufgerufen wird auf den der Pointer zeigt.
    //Bei dem Sphere-Pointer werden zwei Destruktoren aufgerufen, da wenn der Destruktor der Sphere aufgerufen wird, auf welche der Pointer zeigt, automatisch auch noch der Destruktor der Basisklasse aufgerufen wird.
    //Wenn man virtual verwendet wird auch für den Shape-Pointer der Destruktor der Sphere-Klasse aufgerufen, da der Destruktor des Pointers virtual und Sphere die abgeleitete Klasse der Basisklasse Shape ist.
}*/

int main(int argc, char *argv[])
{
  return Catch::Session().run(argc, argv);
}
<|endoftext|>


<commit_before>// Project Dependencies
#include <jnipp.h>

// Local Dependencies
#include "testing.h"

TEST(Vm_detectsJreInstall)
{
	try
	{
		jni::Vm vm;
	}
	catch (jni::InitializationException&)
	{
		ASSERT(0);
		return;
	}

	ASSERT(1);
}

TEST(VM_notAllowedMultipleVms)
{
	try
	{
		jni::Vm secondVm;	// Throws an exception.
	}
	catch (jni::InitializationException&)
	{
		ASSERT(1);
		return;
	}

	ASSERT(0);
}

TEST(Class_findByName)
{
	jni::Class cls("java/lang/String");

	ASSERT(!cls.isNull());
}

TEST(Class_newInstance)
{
	jni::Object str = jni::Class("java/lang/String").newInstance();

	ASSERT(!str.isNull());
}

TEST(Class_newInstance_withArgs)
{
	jni::Object str1 = jni::Class("java/lang/String").newInstance("Testing...");
	jni::Object str2 = jni::Class("java/lang/String").newInstance(L"Testing...");

	ASSERT(!str1.isNull());
	ASSERT(!str2.isNull());
}

TEST(Class_getStaticField)
{
	jni::field_t field = jni::Class("java/lang/Integer").getStaticField("MAX_VALUE", "I");

	ASSERT(field);
}

TEST(Class_getMethod)
{
	jni::method_t method = jni::Class("java/lang/Integer").getMethod("intValue", "()I");

	ASSERT(method);
}

TEST(Class_getStaticMethod)
{
	jni::method_t method = jni::Class("java/lang/Integer").getStaticMethod("compare", "(II)I");

	ASSERT(method);
}

TEST(Class_get_staticField)
{
	jni::Class Integer("java/lang/Integer");
	jni::field_t field = Integer.getStaticField("SIZE", "I");

	ASSERT(Integer.get<int>(field) == 32);
}

TEST(Class_get_staticField_byName)
{
	jni::Class Integer("java/lang/Integer");

	ASSERT(Integer.get<int>("SIZE") == 32);
}

TEST(Class_call_staticMethod)
{
	jni::Class Integer("java/lang/Integer");
	jni::method_t method = Integer.getStaticMethod("parseInt", "(Ljava/lang/String;)I");

	int i = Integer.call<int>(method, "1000");

	ASSERT(i == 1000);
}

TEST(Class_call_staticMethod_byName)
{
	int i = jni::Class("java/lang/Integer").call<int>("parseInt", "1000");

	ASSERT(i = 1000);
}

TEST(Object_defaultConstructor_isNull)
{
	jni::Object o;

	ASSERT(o.isNull());
}

TEST(Object_copyConstructorIsSameObject)
{
	jni::Object a = jni::Class("java/lang/String").newInstance();
	jni::Object b = a;

	ASSERT(a == b);
}

TEST(Object_moveConstructor)
{
	jni::Object a = jni::Class("java/lang/String").newInstance();
	jni::Object b = std::move(a);

	ASSERT(a.isNull());
	ASSERT(!b.isNull());
}

TEST(Object_call)
{
	jni::Class Integer("java/lang/Integer");
	jni::method_t intValue = Integer.getMethod("intValue", "()I");
	jni::Object i = Integer.newInstance(100);

	ASSERT(i.call<int>(intValue) == 100);
}

TEST(Object_call_byName)
{
	jni::Object i = jni::Class("java/lang/Integer").newInstance(100);

	ASSERT(i.call<int>("intValue") == 100);
}

TEST(Object_call_withArgs)
{
	jni::Class String("java/lang/String");
	jni::method_t charAt = String.getMethod("charAt", "(I)C");
	jni::Object str = String.newInstance("Testing");

	ASSERT(str.call<wchar_t>(charAt, 1) == L'e');
}

TEST(Object_call_byNameWithArgs)
{
	jni::Object str = jni::Class("java/lang/String").newInstance("Testing");

	ASSERT(str.call<wchar_t>("charAt", 1) == L'e');
}

TEST(Arg_bool)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", true);

	ASSERT(str == "true");
}

TEST(Arg_wchar)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", L'X');

	ASSERT(str == "X");
}

TEST(Arg_double)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", 123.0);

	ASSERT(str == "123.0");
}

TEST(Arg_float)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", 123.0f);

	ASSERT(str == "123.0");
}

TEST(Arg_int)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", 123);

	ASSERT(str == "123");
}

TEST(Arg_longLong)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", 123LL);

	ASSERT(str == "123");
}

int main()
{
	// jni::Vm Tests
	RUN_TEST(Vm_detectsJreInstall);
	RUN_TEST(VM_notAllowedMultipleVms);

	{
		jni::Vm vm;

		// jni::Class Tests
		RUN_TEST(Class_findByName);
		RUN_TEST(Class_newInstance);
		RUN_TEST(Class_newInstance_withArgs);
		RUN_TEST(Class_getStaticField);
		RUN_TEST(Class_getMethod);
		RUN_TEST(Class_getStaticMethod);
		RUN_TEST(Class_get_staticField);
		RUN_TEST(Class_get_staticField_byName);
		RUN_TEST(Class_call_staticMethod_byName);

		// jni::Object Tests
		RUN_TEST(Object_defaultConstructor_isNull);
		RUN_TEST(Object_copyConstructorIsSameObject);
		RUN_TEST(Object_moveConstructor);
		RUN_TEST(Object_call);
		RUN_TEST(Object_call_byName);
		RUN_TEST(Object_call_withArgs);
		RUN_TEST(Object_call_byNameWithArgs);

		// Argument Type Tests
		RUN_TEST(Arg_bool);
		RUN_TEST(Arg_wchar);
		RUN_TEST(Arg_double);
		RUN_TEST(Arg_float);
		RUN_TEST(Arg_int);
		RUN_TEST(Arg_longLong);
	}

	std::cout << "Press a key to continue..." << std::endl;
	std::cin.get();
	return 0;
}

<commit_msg>Fixed test case.<commit_after>// Project Dependencies
#include <jnipp.h>

// Local Dependencies
#include "testing.h"

TEST(Vm_detectsJreInstall)
{
	try
	{
		jni::Vm vm;
	}
	catch (jni::InitializationException&)
	{
		ASSERT(0);
		return;
	}

	ASSERT(1);
}

TEST(VM_notAllowedMultipleVms)
{
	try
	{
		jni::Vm firstVm;
		jni::Vm secondVm;	// Throws an exception.
	}
	catch (jni::InitializationException&)
	{
		ASSERT(1);
		return;
	}

	ASSERT(0);
}

TEST(Class_findByName)
{
	jni::Class cls("java/lang/String");

	ASSERT(!cls.isNull());
}

TEST(Class_newInstance)
{
	jni::Object str = jni::Class("java/lang/String").newInstance();

	ASSERT(!str.isNull());
}

TEST(Class_newInstance_withArgs)
{
	jni::Object str1 = jni::Class("java/lang/String").newInstance("Testing...");
	jni::Object str2 = jni::Class("java/lang/String").newInstance(L"Testing...");

	ASSERT(!str1.isNull());
	ASSERT(!str2.isNull());
}

TEST(Class_getStaticField)
{
	jni::field_t field = jni::Class("java/lang/Integer").getStaticField("MAX_VALUE", "I");

	ASSERT(field);
}

TEST(Class_getMethod)
{
	jni::method_t method = jni::Class("java/lang/Integer").getMethod("intValue", "()I");

	ASSERT(method);
}

TEST(Class_getStaticMethod)
{
	jni::method_t method = jni::Class("java/lang/Integer").getStaticMethod("compare", "(II)I");

	ASSERT(method);
}

TEST(Class_get_staticField)
{
	jni::Class Integer("java/lang/Integer");
	jni::field_t field = Integer.getStaticField("SIZE", "I");

	ASSERT(Integer.get<int>(field) == 32);
}

TEST(Class_get_staticField_byName)
{
	jni::Class Integer("java/lang/Integer");

	ASSERT(Integer.get<int>("SIZE") == 32);
}

TEST(Class_call_staticMethod)
{
	jni::Class Integer("java/lang/Integer");
	jni::method_t method = Integer.getStaticMethod("parseInt", "(Ljava/lang/String;)I");

	int i = Integer.call<int>(method, "1000");

	ASSERT(i == 1000);
}

TEST(Class_call_staticMethod_byName)
{
	int i = jni::Class("java/lang/Integer").call<int>("parseInt", "1000");

	ASSERT(i = 1000);
}

TEST(Object_defaultConstructor_isNull)
{
	jni::Object o;

	ASSERT(o.isNull());
}

TEST(Object_copyConstructorIsSameObject)
{
	jni::Object a = jni::Class("java/lang/String").newInstance();
	jni::Object b = a;

	ASSERT(a == b);
}

TEST(Object_moveConstructor)
{
	jni::Object a = jni::Class("java/lang/String").newInstance();
	jni::Object b = std::move(a);

	ASSERT(a.isNull());
	ASSERT(!b.isNull());
}

TEST(Object_call)
{
	jni::Class Integer("java/lang/Integer");
	jni::method_t intValue = Integer.getMethod("intValue", "()I");
	jni::Object i = Integer.newInstance(100);

	ASSERT(i.call<int>(intValue) == 100);
}

TEST(Object_call_byName)
{
	jni::Object i = jni::Class("java/lang/Integer").newInstance(100);

	ASSERT(i.call<int>("intValue") == 100);
}

TEST(Object_call_withArgs)
{
	jni::Class String("java/lang/String");
	jni::method_t charAt = String.getMethod("charAt", "(I)C");
	jni::Object str = String.newInstance("Testing");

	ASSERT(str.call<wchar_t>(charAt, 1) == L'e');
}

TEST(Object_call_byNameWithArgs)
{
	jni::Object str = jni::Class("java/lang/String").newInstance("Testing");

	ASSERT(str.call<wchar_t>("charAt", 1) == L'e');
}

TEST(Arg_bool)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", true);

	ASSERT(str == "true");
}

TEST(Arg_wchar)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", L'X');

	ASSERT(str == "X");
}

TEST(Arg_double)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", 123.0);

	ASSERT(str == "123.0");
}

TEST(Arg_float)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", 123.0f);

	ASSERT(str == "123.0");
}

TEST(Arg_int)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", 123);

	ASSERT(str == "123");
}

TEST(Arg_longLong)
{
	jni::String str = jni::Class("java/lang/String").call<jni::String>("valueOf", 123LL);

	ASSERT(str == "123");
}

int main()
{
	// jni::Vm Tests
	RUN_TEST(Vm_detectsJreInstall);
	RUN_TEST(VM_notAllowedMultipleVms);

	{
		jni::Vm vm;

		// jni::Class Tests
		RUN_TEST(Class_findByName);
		RUN_TEST(Class_newInstance);
		RUN_TEST(Class_newInstance_withArgs);
		RUN_TEST(Class_getStaticField);
		RUN_TEST(Class_getMethod);
		RUN_TEST(Class_getStaticMethod);
		RUN_TEST(Class_get_staticField);
		RUN_TEST(Class_get_staticField_byName);
		RUN_TEST(Class_call_staticMethod_byName);

		// jni::Object Tests
		RUN_TEST(Object_defaultConstructor_isNull);
		RUN_TEST(Object_copyConstructorIsSameObject);
		RUN_TEST(Object_moveConstructor);
		RUN_TEST(Object_call);
		RUN_TEST(Object_call_byName);
		RUN_TEST(Object_call_withArgs);
		RUN_TEST(Object_call_byNameWithArgs);

		// Argument Type Tests
		RUN_TEST(Arg_bool);
		RUN_TEST(Arg_wchar);
		RUN_TEST(Arg_double);
		RUN_TEST(Arg_float);
		RUN_TEST(Arg_int);
		RUN_TEST(Arg_longLong);
	}

	std::cout << "Press a key to continue..." << std::endl;
	std::cin.get();
	return 0;
}

<|endoftext|>


<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <NDK/Widgets/TextAreaWidget.hpp>

namespace Ndk
{
	inline void TextAreaWidget::Clear()
	{
		m_cursorPosition.MakeZero();
		m_drawer.Clear();
		m_textSprite->Update(m_drawer);

		RefreshCursor();
	}

	inline void TextAreaWidget::EnableMultiline(bool enable)
	{
		m_multiLineEnabled = enable;
	}

	inline unsigned int TextAreaWidget::GetCharacterSize() const
	{
		return m_drawer.GetCharacterSize();
	}

	inline const Nz::Vector2ui& TextAreaWidget::GetCursorPosition() const
	{
		return m_cursorPosition;
	}

	inline const Nz::String& TextAreaWidget::GetDisplayText() const
	{
		return m_drawer.GetText();
	}

	inline std::size_t TextAreaWidget::GetGlyphIndex(const Nz::Vector2ui& cursorPosition)
	{
		std::size_t glyphIndex = m_drawer.GetLine(cursorPosition.y).glyphIndex + cursorPosition.x;
		if (m_drawer.GetLineCount() > cursorPosition.y + 1)
			glyphIndex = std::min(glyphIndex, m_drawer.GetLine(cursorPosition.y + 1).glyphIndex - 1);
		else
			glyphIndex = std::min(glyphIndex, m_drawer.GetGlyphCount());

		return glyphIndex;
	}

	inline EchoMode TextAreaWidget::GetEchoMode() const
	{
		return m_echoMode;
	}

	inline const Nz::String& TextAreaWidget::GetText() const
	{
		return m_text;
	}

	inline const Nz::Color& TextAreaWidget::GetTextColor() const
	{
		return m_drawer.GetColor();
	}

	inline bool Ndk::TextAreaWidget::IsMultilineEnabled() const
	{
		return m_multiLineEnabled;
	}

	inline bool TextAreaWidget::IsReadOnly() const
	{
		return m_readOnly;
	}

	inline void TextAreaWidget::MoveCursor(int offset)
	{
		std::size_t cursorGlyph = GetGlyphIndex(m_cursorPosition);
		if (offset >= 0)
			SetCursorPosition(cursorGlyph + static_cast<std::size_t>(offset));
		else
		{
			std::size_t nOffset = static_cast<std::size_t>(-offset);
			if (nOffset >= cursorGlyph)
				SetCursorPosition(0);
			else
				SetCursorPosition(cursorGlyph - nOffset);
		}
	}

	inline void TextAreaWidget::MoveCursor(const Nz::Vector2i& offset)
	{
		auto ClampOffset = [] (unsigned int cursorPosition, int cursorOffset) -> unsigned int
		{
			if (cursorOffset >= 0)
				return cursorPosition + cursorOffset;
			else
			{
				unsigned int nOffset = static_cast<unsigned int>(-cursorOffset);
				if (nOffset >= cursorPosition)
					return 0;
				else
					return cursorPosition - nOffset;
			}
		};

		Nz::Vector2ui cursorPosition = m_cursorPosition;
		cursorPosition.x = ClampOffset(static_cast<unsigned int>(cursorPosition.x), offset.x);
		cursorPosition.y = ClampOffset(static_cast<unsigned int>(cursorPosition.y), offset.y);

		SetCursorPosition(cursorPosition);
	}

	inline void TextAreaWidget::SetCharacterSize(unsigned int characterSize)
	{
		m_drawer.SetCharacterSize(characterSize);
	}

	inline void TextAreaWidget::SetCursorPosition(std::size_t glyphIndex)
	{
		OnTextAreaCursorMove(this, &glyphIndex);

		glyphIndex = std::min(glyphIndex, m_drawer.GetGlyphCount());

		std::size_t lineCount = m_drawer.GetLineCount();
		std::size_t line = 0U;
		for (std::size_t i = line + 1; i < lineCount; ++i)
		{
			if (m_drawer.GetLine(i).glyphIndex > glyphIndex)
				break;

			line = i;
		}

		const auto& lineInfo = m_drawer.GetLine(line);

		m_cursorPosition.y = static_cast<unsigned int>(line);
		m_cursorPosition.x = static_cast<unsigned int>(glyphIndex - lineInfo.glyphIndex);

		RefreshCursor();
	}

	inline void TextAreaWidget::SetCursorPosition(Nz::Vector2ui cursorPosition)
	{
		std::size_t lineCount = m_drawer.GetLineCount();
		if (cursorPosition.y >= lineCount)
			cursorPosition.y = static_cast<unsigned int>(lineCount - 1);

		m_cursorPosition = cursorPosition;

		const auto& lineInfo = m_drawer.GetLine(cursorPosition.y);
		if (cursorPosition.y + 1 < lineCount)
		{
			const auto& nextLineInfo = m_drawer.GetLine(cursorPosition.y + 1);
			cursorPosition.x = std::min(cursorPosition.x, static_cast<unsigned int>(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1));
		}

		std::size_t glyphIndex = lineInfo.glyphIndex + cursorPosition.x;

		OnTextAreaCursorMove(this, &glyphIndex);

		RefreshCursor();
	}

	inline void TextAreaWidget::SetEchoMode(EchoMode echoMode)
	{
		m_echoMode = echoMode;

		UpdateDisplayText();
	}

	inline void TextAreaWidget::SetReadOnly(bool readOnly)
	{
		m_readOnly = readOnly;
		m_cursorEntity->Enable(!m_readOnly && HasFocus());
	}

	inline void TextAreaWidget::SetText(const Nz::String& text)
	{
		m_text = text;
		OnTextChanged(this, m_text);

		UpdateDisplayText();
	}

	inline void TextAreaWidget::SetTextColor(const Nz::Color& text)
	{
		m_drawer.SetColor(text);

		m_textSprite->Update(m_drawer);
	}
}
<commit_msg>Sdk/TextAreaWidget: Fix Clear<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <NDK/Widgets/TextAreaWidget.hpp>

namespace Ndk
{
	inline void TextAreaWidget::Clear()
	{
		m_cursorPosition.MakeZero();
		m_drawer.Clear();
		m_text.Clear();
		m_textSprite->Update(m_drawer);

		RefreshCursor();
		OnTextChanged(this, m_text);
	}

	inline void TextAreaWidget::EnableMultiline(bool enable)
	{
		m_multiLineEnabled = enable;
	}

	inline unsigned int TextAreaWidget::GetCharacterSize() const
	{
		return m_drawer.GetCharacterSize();
	}

	inline const Nz::Vector2ui& TextAreaWidget::GetCursorPosition() const
	{
		return m_cursorPosition;
	}

	inline const Nz::String& TextAreaWidget::GetDisplayText() const
	{
		return m_drawer.GetText();
	}

	inline std::size_t TextAreaWidget::GetGlyphIndex(const Nz::Vector2ui& cursorPosition)
	{
		std::size_t glyphIndex = m_drawer.GetLine(cursorPosition.y).glyphIndex + cursorPosition.x;
		if (m_drawer.GetLineCount() > cursorPosition.y + 1)
			glyphIndex = std::min(glyphIndex, m_drawer.GetLine(cursorPosition.y + 1).glyphIndex - 1);
		else
			glyphIndex = std::min(glyphIndex, m_drawer.GetGlyphCount());

		return glyphIndex;
	}

	inline EchoMode TextAreaWidget::GetEchoMode() const
	{
		return m_echoMode;
	}

	inline const Nz::String& TextAreaWidget::GetText() const
	{
		return m_text;
	}

	inline const Nz::Color& TextAreaWidget::GetTextColor() const
	{
		return m_drawer.GetColor();
	}

	inline bool Ndk::TextAreaWidget::IsMultilineEnabled() const
	{
		return m_multiLineEnabled;
	}

	inline bool TextAreaWidget::IsReadOnly() const
	{
		return m_readOnly;
	}

	inline void TextAreaWidget::MoveCursor(int offset)
	{
		std::size_t cursorGlyph = GetGlyphIndex(m_cursorPosition);
		if (offset >= 0)
			SetCursorPosition(cursorGlyph + static_cast<std::size_t>(offset));
		else
		{
			std::size_t nOffset = static_cast<std::size_t>(-offset);
			if (nOffset >= cursorGlyph)
				SetCursorPosition(0);
			else
				SetCursorPosition(cursorGlyph - nOffset);
		}
	}

	inline void TextAreaWidget::MoveCursor(const Nz::Vector2i& offset)
	{
		auto ClampOffset = [] (unsigned int cursorPosition, int cursorOffset) -> unsigned int
		{
			if (cursorOffset >= 0)
				return cursorPosition + cursorOffset;
			else
			{
				unsigned int nOffset = static_cast<unsigned int>(-cursorOffset);
				if (nOffset >= cursorPosition)
					return 0;
				else
					return cursorPosition - nOffset;
			}
		};

		Nz::Vector2ui cursorPosition = m_cursorPosition;
		cursorPosition.x = ClampOffset(static_cast<unsigned int>(cursorPosition.x), offset.x);
		cursorPosition.y = ClampOffset(static_cast<unsigned int>(cursorPosition.y), offset.y);

		SetCursorPosition(cursorPosition);
	}

	inline void TextAreaWidget::SetCharacterSize(unsigned int characterSize)
	{
		m_drawer.SetCharacterSize(characterSize);
	}

	inline void TextAreaWidget::SetCursorPosition(std::size_t glyphIndex)
	{
		OnTextAreaCursorMove(this, &glyphIndex);

		glyphIndex = std::min(glyphIndex, m_drawer.GetGlyphCount());

		std::size_t lineCount = m_drawer.GetLineCount();
		std::size_t line = 0U;
		for (std::size_t i = line + 1; i < lineCount; ++i)
		{
			if (m_drawer.GetLine(i).glyphIndex > glyphIndex)
				break;

			line = i;
		}

		const auto& lineInfo = m_drawer.GetLine(line);

		m_cursorPosition.y = static_cast<unsigned int>(line);
		m_cursorPosition.x = static_cast<unsigned int>(glyphIndex - lineInfo.glyphIndex);

		RefreshCursor();
	}

	inline void TextAreaWidget::SetCursorPosition(Nz::Vector2ui cursorPosition)
	{
		std::size_t lineCount = m_drawer.GetLineCount();
		if (cursorPosition.y >= lineCount)
			cursorPosition.y = static_cast<unsigned int>(lineCount - 1);

		m_cursorPosition = cursorPosition;

		const auto& lineInfo = m_drawer.GetLine(cursorPosition.y);
		if (cursorPosition.y + 1 < lineCount)
		{
			const auto& nextLineInfo = m_drawer.GetLine(cursorPosition.y + 1);
			cursorPosition.x = std::min(cursorPosition.x, static_cast<unsigned int>(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1));
		}

		std::size_t glyphIndex = lineInfo.glyphIndex + cursorPosition.x;

		OnTextAreaCursorMove(this, &glyphIndex);

		RefreshCursor();
	}

	inline void TextAreaWidget::SetEchoMode(EchoMode echoMode)
	{
		m_echoMode = echoMode;

		UpdateDisplayText();
	}

	inline void TextAreaWidget::SetReadOnly(bool readOnly)
	{
		m_readOnly = readOnly;
		m_cursorEntity->Enable(!m_readOnly && HasFocus());
	}

	inline void TextAreaWidget::SetText(const Nz::String& text)
	{
		m_text = text;
		OnTextChanged(this, m_text);

		UpdateDisplayText();
	}

	inline void TextAreaWidget::SetTextColor(const Nz::Color& text)
	{
		m_drawer.SetColor(text);

		m_textSprite->Update(m_drawer);
	}
}
<|endoftext|>


<commit_before>

fun range : (n : integer) -> ([integer])
  for x in 1 .. n
  initially acc = []:
    x :: acc
<commit_msg>forward and reverse range;<commit_after>

fun range : (n : integer) -> ([integer])
  # NOTE descending values of x
  for x in n .. 1
  initially acc = []:
    x :: acc

fun range_reverse : (n : integer) -> ([integer])
  for x in 1 .. n
  initially acc = []:
    x :: acc
<|endoftext|>


<commit_before>/*************************************************
* DER Encoder Source File                        *
* (C) 1999-2006 The Botan Project                *
*************************************************/

#include <botan/der_enc.h>
#include <botan/asn1_int.h>
#include <botan/bigint.h>
#include <botan/bit_ops.h>
#include <botan/parsing.h>
#include <algorithm>

namespace Botan {

namespace {

/*************************************************
* DER encode an ASN.1 type tag                   *
*************************************************/
SecureVector<byte> encode_tag(ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if((class_tag | 0xE0) != 0xE0)
      throw Encoding_Error("DER_Encoder: Invalid class tag " +
                           to_string(class_tag));

   SecureVector<byte> encoded_tag;
   if(type_tag <= 30)
      encoded_tag.append((byte)(type_tag | class_tag));
   else
      {
      u32bit blocks = high_bit(type_tag) + 6;
      blocks = (blocks - (blocks % 7)) / 7;

      encoded_tag.append(class_tag | 0x1F);
      for(u32bit k = 0; k != blocks - 1; ++k)
         encoded_tag.append(0x80 | ((type_tag >> 7*(blocks-k-1)) & 0x7F));
      encoded_tag.append(type_tag & 0x7F);
      }

   return encoded_tag;
   }

/*************************************************
* DER encode an ASN.1 length field               *
*************************************************/
SecureVector<byte> encode_length(u32bit length)
   {
   SecureVector<byte> encoded_length;
   if(length <= 127)
      encoded_length.append((byte)length);
   else
      {
      const u32bit top_byte = significant_bytes(length);
      encoded_length.append((byte)(0x80 | top_byte));
      for(u32bit j = 4-top_byte; j != 4; ++j)
         encoded_length.append(get_byte(j, length));
      }
   return encoded_length;
   }

/*************************************************
* A comparison functor for sorting SET objects   *
*************************************************/
class DER_Cmp
   {
   public:
      bool operator()(const MemoryRegion<byte>&,
                      const MemoryRegion<byte>&) const;
   };

/*************************************************
* Compare two encodings, as specified by X.690   *
*************************************************/
bool DER_Cmp::operator()(const MemoryRegion<byte>& a,
                         const MemoryRegion<byte>& b) const
   {
   // FIXME: use lexicographical_compare
   if(a.size() < b.size()) return true;
   if(a.size() > b.size()) return false;

   for(u32bit j = 0; j != a.size(); ++j)
      {
      if(a[j] < b[j]) return true;
      if(a[j] > b[j]) return false;
      }
   return false;
   }

}

/*************************************************
* Return the encoded SEQUENCE/SET                *
*************************************************/
SecureVector<byte> DER_Encoder::DER_Sequence::get_contents()
   {
   const ASN1_Tag real_class_tag = ASN1_Tag(class_tag | CONSTRUCTED);

   SecureVector<byte> encoded_tag = encode_tag(type_tag, real_class_tag);

   if(type_tag == SET)
      {
      std::sort(set_contents.begin(), set_contents.end(), DER_Cmp());
      for(u32bit j = 0; j != set_contents.size(); ++j)
         contents.append(set_contents[j]);
      set_contents.clear();
      }

   SecureVector<byte> encoded_length = encode_length(contents.size());

   SecureVector<byte> retval;
   retval.append(encoded_tag);
   retval.append(encoded_length);
   retval.append(contents);
   contents.destroy();
   return retval;
   }

/*************************************************
* Add an encoded value to the SEQUENCE/SET       *
*************************************************/
void DER_Encoder::DER_Sequence::add_bytes(const byte data[], u32bit length)
   {
   if(type_tag == SET)
      set_contents.push_back(SecureVector<byte>(data, length));
   else
      contents.append(data, length);
   }

/*************************************************
* Return the type and class taggings             *
*************************************************/
ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const
   {
   return ASN1_Tag(type_tag | class_tag);
   }

/*************************************************
* DER_Sequence Constructor                       *
*************************************************/
DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) :
   type_tag(t1), class_tag(t2)
   {
   }

/*************************************************
* Return the encoded contents                    *
*************************************************/
SecureVector<byte> DER_Encoder::get_contents()
   {
   if(subsequences.size() != 0)
      throw Invalid_State("DER_Encoder: Sequence hasn't been marked done");

   SecureVector<byte> retval;
   retval = contents;
   contents.destroy();
   return retval;
   }

/*************************************************
* Start a new ASN.1 SEQUENCE/SET/EXPLICIT        *
*************************************************/
DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag,
                                     ASN1_Tag class_tag)
   {
   subsequences.push_back(DER_Sequence(type_tag, class_tag));
   return (*this);
   }

/*************************************************
* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT *
*************************************************/
DER_Encoder& DER_Encoder::end_cons()
   {
   if(subsequences.empty())
      throw Invalid_State("DER_Encoder::end_cons: No such sequence");

   SecureVector<byte> seq = subsequences[subsequences.size()-1].get_contents();
   subsequences.pop_back();
   raw_bytes(seq);
   return (*this);
   }

/*************************************************
* Start a new ASN.1 EXPLICIT encoding            *
*************************************************/
DER_Encoder& DER_Encoder::start_explicit(u16bit type_no)
   {
   ASN1_Tag type_tag = (ASN1_Tag)type_no;

   if(type_tag == SET)
      throw Internal_Error("DER_Encoder.start_explicit(SET); cannot perform");

   return start_cons(type_tag, CONTEXT_SPECIFIC);
   }

/*************************************************
* Finish the current ASN.1 EXPLICIT encoding     *
*************************************************/
DER_Encoder& DER_Encoder::end_explicit()
   {
   return end_cons();
   }

/*************************************************
* Write raw bytes into the stream                *
*************************************************/
DER_Encoder& DER_Encoder::raw_bytes(const MemoryRegion<byte>& val)
   {
   return raw_bytes(val.begin(), val.size());
   }

/*************************************************
* Write raw bytes into the stream                *
*************************************************/
DER_Encoder& DER_Encoder::raw_bytes(const byte bytes[], u32bit length)
   {
   if(subsequences.size())
      subsequences[subsequences.size()-1].add_bytes(bytes, length);
   else
      contents.append(bytes, length);

   return (*this);
   }

/*************************************************
* Encode a NULL object                           *
*************************************************/
DER_Encoder& DER_Encoder::encode_null()
   {
   return add_object(NULL_TAG, UNIVERSAL, 0, 0);
   }

/*************************************************
* DER encode a BOOLEAN                           *
*************************************************/
DER_Encoder& DER_Encoder::encode(bool is_true)
   {
   return encode(is_true, BOOLEAN, UNIVERSAL);
   }

/*************************************************
* DER encode a small INTEGER                     *
*************************************************/
DER_Encoder& DER_Encoder::encode(u32bit n)
   {
   return encode(BigInt(n), INTEGER, UNIVERSAL);
   }

/*************************************************
* DER encode a small INTEGER                     *
*************************************************/
DER_Encoder& DER_Encoder::encode(const BigInt& n)
   {
   return encode(n, INTEGER, UNIVERSAL);
   }

/*************************************************
* DER encode an OCTET STRING or BIT STRING       *
*************************************************/
DER_Encoder& DER_Encoder::encode(const MemoryRegion<byte>& bytes,
                                 ASN1_Tag real_type)
   {
   return encode(bytes.begin(), bytes.size(),
                 real_type, real_type, UNIVERSAL);
   }

/*************************************************
* Encode this object                             *
*************************************************/
DER_Encoder& DER_Encoder::encode(const byte bytes[], u32bit length,
                                 ASN1_Tag real_type)
   {
   return encode(bytes, length, real_type, real_type, UNIVERSAL);
   }

/*************************************************
* DER encode a BOOLEAN                           *
*************************************************/
DER_Encoder& DER_Encoder::encode(bool is_true,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   byte val = is_true ? 0xFF : 0x00;
   return add_object(type_tag, class_tag, &val, 1);
   }

/*************************************************
* DER encode a small INTEGER                     *
*************************************************/
DER_Encoder& DER_Encoder::encode(u32bit n,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   return encode(BigInt(n), type_tag, class_tag);
   }

/*************************************************
* DER encode an INTEGER                          *
*************************************************/
DER_Encoder& DER_Encoder::encode(const BigInt& n,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if(n == 0)
      return add_object(type_tag, class_tag, 0);

   bool extra_zero = (n.bits() % 8 == 0);
   SecureVector<byte> contents(extra_zero + n.bytes());
   BigInt::encode(contents.begin() + extra_zero, n);
   if(n < 0)
      {
      for(u32bit j = 0; j != contents.size(); ++j)
         contents[j] = ~contents[j];
      for(u32bit j = contents.size(); j > 0; --j)
         if(++contents[j-1])
            break;
      }

   return add_object(type_tag, class_tag, contents);
   }

/*************************************************
* DER encode an OCTET STRING or BIT STRING       *
*************************************************/
DER_Encoder& DER_Encoder::encode(const MemoryRegion<byte>& bytes,
                                 ASN1_Tag real_type,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   return encode(bytes.begin(), bytes.size(),
                 real_type, type_tag, class_tag);
   }

/*************************************************
* DER encode an OCTET STRING or BIT STRING       *
*************************************************/
DER_Encoder& DER_Encoder::encode(const byte bytes[], u32bit length,
                                 ASN1_Tag real_type,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if(real_type != OCTET_STRING && real_type != BIT_STRING)
      throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string");

   if(real_type == BIT_STRING)
      {
      SecureVector<byte> encoded;
      encoded.append(0);
      encoded.append(bytes, length);
      return add_object(type_tag, class_tag, encoded);
      }
   else
      return add_object(type_tag, class_tag, bytes, length);
   }

/*************************************************
* Conditionally write some values to the stream  *
*************************************************/
DER_Encoder& DER_Encoder::encode_if(bool cond, DER_Encoder& codec)
   {
   if(cond)
      return raw_bytes(codec.get_contents());
   return (*this);
   }

/*************************************************
* Request for an object to encode itself         *
*************************************************/
DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj)
   {
   obj.encode_into(*this);
   return (*this);
   }

/*************************************************
* Write the encoding of the byte(s)              *
*************************************************/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const byte rep[], u32bit length)
   {
   SecureVector<byte> encoded_tag = encode_tag(type_tag, class_tag);
   SecureVector<byte> encoded_length = encode_length(length);

   SecureVector<byte> buffer;
   buffer.append(encoded_tag);
   buffer.append(encoded_length);
   buffer.append(rep, length);

   return raw_bytes(buffer);
   }

/*************************************************
* Write the encoding of the byte(s)              *
*************************************************/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const MemoryRegion<byte>& rep_buf)
   {
   const byte* rep = rep_buf.begin();
   const u32bit rep_len = rep_buf.size();
   return add_object(type_tag, class_tag, rep, rep_len);
   }

/*************************************************
* Write the encoding of the byte(s)              *
*************************************************/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const std::string& rep_str)
   {
   const byte* rep = (const byte*)rep_str.c_str();
   const u32bit rep_len = rep_str.size();
   return add_object(type_tag, class_tag, rep, rep_len);
   }

/*************************************************
* Write the encoding of the byte                 *
*************************************************/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag,
                                     ASN1_Tag class_tag, byte rep)
   {
   return add_object(type_tag, class_tag, &rep, 1);
   }

}
<commit_msg>Turns out that DER_Cmp's comparison is exactly the same as the one built into MemoryRegion (no real surprise, as they are both simple byte-wise lexicographical compares), so remove it and just use the MemoryRegion<>::operator< for sorting sets<commit_after>/*************************************************
* DER Encoder Source File                        *
* (C) 1999-2006 The Botan Project                *
*************************************************/

#include <botan/der_enc.h>
#include <botan/asn1_int.h>
#include <botan/bigint.h>
#include <botan/bit_ops.h>
#include <botan/parsing.h>
#include <algorithm>

namespace Botan {

namespace {

/*************************************************
* DER encode an ASN.1 type tag                   *
*************************************************/
SecureVector<byte> encode_tag(ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if((class_tag | 0xE0) != 0xE0)
      throw Encoding_Error("DER_Encoder: Invalid class tag " +
                           to_string(class_tag));

   SecureVector<byte> encoded_tag;
   if(type_tag <= 30)
      encoded_tag.append((byte)(type_tag | class_tag));
   else
      {
      u32bit blocks = high_bit(type_tag) + 6;
      blocks = (blocks - (blocks % 7)) / 7;

      encoded_tag.append(class_tag | 0x1F);
      for(u32bit k = 0; k != blocks - 1; ++k)
         encoded_tag.append(0x80 | ((type_tag >> 7*(blocks-k-1)) & 0x7F));
      encoded_tag.append(type_tag & 0x7F);
      }

   return encoded_tag;
   }

/*************************************************
* DER encode an ASN.1 length field               *
*************************************************/
SecureVector<byte> encode_length(u32bit length)
   {
   SecureVector<byte> encoded_length;
   if(length <= 127)
      encoded_length.append((byte)length);
   else
      {
      const u32bit top_byte = significant_bytes(length);
      encoded_length.append((byte)(0x80 | top_byte));
      for(u32bit j = 4-top_byte; j != 4; ++j)
         encoded_length.append(get_byte(j, length));
      }
   return encoded_length;
   }

}

/*************************************************
* Return the encoded SEQUENCE/SET                *
*************************************************/
SecureVector<byte> DER_Encoder::DER_Sequence::get_contents()
   {
   const ASN1_Tag real_class_tag = ASN1_Tag(class_tag | CONSTRUCTED);

   SecureVector<byte> encoded_tag = encode_tag(type_tag, real_class_tag);

   if(type_tag == SET)
      {
      std::sort(set_contents.begin(), set_contents.end());
      for(u32bit j = 0; j != set_contents.size(); ++j)
         contents.append(set_contents[j]);
      set_contents.clear();
      }

   SecureVector<byte> encoded_length = encode_length(contents.size());

   SecureVector<byte> retval;
   retval.append(encoded_tag);
   retval.append(encoded_length);
   retval.append(contents);
   contents.destroy();
   return retval;
   }

/*************************************************
* Add an encoded value to the SEQUENCE/SET       *
*************************************************/
void DER_Encoder::DER_Sequence::add_bytes(const byte data[], u32bit length)
   {
   if(type_tag == SET)
      set_contents.push_back(SecureVector<byte>(data, length));
   else
      contents.append(data, length);
   }

/*************************************************
* Return the type and class taggings             *
*************************************************/
ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const
   {
   return ASN1_Tag(type_tag | class_tag);
   }

/*************************************************
* DER_Sequence Constructor                       *
*************************************************/
DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) :
   type_tag(t1), class_tag(t2)
   {
   }

/*************************************************
* Return the encoded contents                    *
*************************************************/
SecureVector<byte> DER_Encoder::get_contents()
   {
   if(subsequences.size() != 0)
      throw Invalid_State("DER_Encoder: Sequence hasn't been marked done");

   SecureVector<byte> retval;
   retval = contents;
   contents.destroy();
   return retval;
   }

/*************************************************
* Start a new ASN.1 SEQUENCE/SET/EXPLICIT        *
*************************************************/
DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag,
                                     ASN1_Tag class_tag)
   {
   subsequences.push_back(DER_Sequence(type_tag, class_tag));
   return (*this);
   }

/*************************************************
* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT *
*************************************************/
DER_Encoder& DER_Encoder::end_cons()
   {
   if(subsequences.empty())
      throw Invalid_State("DER_Encoder::end_cons: No such sequence");

   SecureVector<byte> seq = subsequences[subsequences.size()-1].get_contents();
   subsequences.pop_back();
   raw_bytes(seq);
   return (*this);
   }

/*************************************************
* Start a new ASN.1 EXPLICIT encoding            *
*************************************************/
DER_Encoder& DER_Encoder::start_explicit(u16bit type_no)
   {
   ASN1_Tag type_tag = (ASN1_Tag)type_no;

   if(type_tag == SET)
      throw Internal_Error("DER_Encoder.start_explicit(SET); cannot perform");

   return start_cons(type_tag, CONTEXT_SPECIFIC);
   }

/*************************************************
* Finish the current ASN.1 EXPLICIT encoding     *
*************************************************/
DER_Encoder& DER_Encoder::end_explicit()
   {
   return end_cons();
   }

/*************************************************
* Write raw bytes into the stream                *
*************************************************/
DER_Encoder& DER_Encoder::raw_bytes(const MemoryRegion<byte>& val)
   {
   return raw_bytes(val.begin(), val.size());
   }

/*************************************************
* Write raw bytes into the stream                *
*************************************************/
DER_Encoder& DER_Encoder::raw_bytes(const byte bytes[], u32bit length)
   {
   if(subsequences.size())
      subsequences[subsequences.size()-1].add_bytes(bytes, length);
   else
      contents.append(bytes, length);

   return (*this);
   }

/*************************************************
* Encode a NULL object                           *
*************************************************/
DER_Encoder& DER_Encoder::encode_null()
   {
   return add_object(NULL_TAG, UNIVERSAL, 0, 0);
   }

/*************************************************
* DER encode a BOOLEAN                           *
*************************************************/
DER_Encoder& DER_Encoder::encode(bool is_true)
   {
   return encode(is_true, BOOLEAN, UNIVERSAL);
   }

/*************************************************
* DER encode a small INTEGER                     *
*************************************************/
DER_Encoder& DER_Encoder::encode(u32bit n)
   {
   return encode(BigInt(n), INTEGER, UNIVERSAL);
   }

/*************************************************
* DER encode a small INTEGER                     *
*************************************************/
DER_Encoder& DER_Encoder::encode(const BigInt& n)
   {
   return encode(n, INTEGER, UNIVERSAL);
   }

/*************************************************
* DER encode an OCTET STRING or BIT STRING       *
*************************************************/
DER_Encoder& DER_Encoder::encode(const MemoryRegion<byte>& bytes,
                                 ASN1_Tag real_type)
   {
   return encode(bytes.begin(), bytes.size(),
                 real_type, real_type, UNIVERSAL);
   }

/*************************************************
* Encode this object                             *
*************************************************/
DER_Encoder& DER_Encoder::encode(const byte bytes[], u32bit length,
                                 ASN1_Tag real_type)
   {
   return encode(bytes, length, real_type, real_type, UNIVERSAL);
   }

/*************************************************
* DER encode a BOOLEAN                           *
*************************************************/
DER_Encoder& DER_Encoder::encode(bool is_true,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   byte val = is_true ? 0xFF : 0x00;
   return add_object(type_tag, class_tag, &val, 1);
   }

/*************************************************
* DER encode a small INTEGER                     *
*************************************************/
DER_Encoder& DER_Encoder::encode(u32bit n,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   return encode(BigInt(n), type_tag, class_tag);
   }

/*************************************************
* DER encode an INTEGER                          *
*************************************************/
DER_Encoder& DER_Encoder::encode(const BigInt& n,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if(n == 0)
      return add_object(type_tag, class_tag, 0);

   bool extra_zero = (n.bits() % 8 == 0);
   SecureVector<byte> contents(extra_zero + n.bytes());
   BigInt::encode(contents.begin() + extra_zero, n);
   if(n < 0)
      {
      for(u32bit j = 0; j != contents.size(); ++j)
         contents[j] = ~contents[j];
      for(u32bit j = contents.size(); j > 0; --j)
         if(++contents[j-1])
            break;
      }

   return add_object(type_tag, class_tag, contents);
   }

/*************************************************
* DER encode an OCTET STRING or BIT STRING       *
*************************************************/
DER_Encoder& DER_Encoder::encode(const MemoryRegion<byte>& bytes,
                                 ASN1_Tag real_type,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   return encode(bytes.begin(), bytes.size(),
                 real_type, type_tag, class_tag);
   }

/*************************************************
* DER encode an OCTET STRING or BIT STRING       *
*************************************************/
DER_Encoder& DER_Encoder::encode(const byte bytes[], u32bit length,
                                 ASN1_Tag real_type,
                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
   {
   if(real_type != OCTET_STRING && real_type != BIT_STRING)
      throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string");

   if(real_type == BIT_STRING)
      {
      SecureVector<byte> encoded;
      encoded.append(0);
      encoded.append(bytes, length);
      return add_object(type_tag, class_tag, encoded);
      }
   else
      return add_object(type_tag, class_tag, bytes, length);
   }

/*************************************************
* Conditionally write some values to the stream  *
*************************************************/
DER_Encoder& DER_Encoder::encode_if(bool cond, DER_Encoder& codec)
   {
   if(cond)
      return raw_bytes(codec.get_contents());
   return (*this);
   }

/*************************************************
* Request for an object to encode itself         *
*************************************************/
DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj)
   {
   obj.encode_into(*this);
   return (*this);
   }

/*************************************************
* Write the encoding of the byte(s)              *
*************************************************/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const byte rep[], u32bit length)
   {
   SecureVector<byte> encoded_tag = encode_tag(type_tag, class_tag);
   SecureVector<byte> encoded_length = encode_length(length);

   SecureVector<byte> buffer;
   buffer.append(encoded_tag);
   buffer.append(encoded_length);
   buffer.append(rep, length);

   return raw_bytes(buffer);
   }

/*************************************************
* Write the encoding of the byte(s)              *
*************************************************/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const MemoryRegion<byte>& rep_buf)
   {
   const byte* rep = rep_buf.begin();
   const u32bit rep_len = rep_buf.size();
   return add_object(type_tag, class_tag, rep, rep_len);
   }

/*************************************************
* Write the encoding of the byte(s)              *
*************************************************/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
                                     const std::string& rep_str)
   {
   const byte* rep = (const byte*)rep_str.c_str();
   const u32bit rep_len = rep_str.size();
   return add_object(type_tag, class_tag, rep, rep_len);
   }

/*************************************************
* Write the encoding of the byte                 *
*************************************************/
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag,
                                     ASN1_Tag class_tag, byte rep)
   {
   return add_object(type_tag, class_tag, &rep, 1);
   }

}
<|endoftext|>


<commit_before><commit_msg>Detach verify thread from NSPR on linux.<commit_after><|endoftext|>