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

// File: vogl_port_posix.cpp

#if !defined(PLATFORM_POSIX)
    #error "vogl_port_posix should not be compiled on non-POSIX platforms."
#endif

#include "vogl_port.h"
#include <dlfcn.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <paths.h>

int plat_chdir(const char* path)
{
    return chdir(path);
}

char* plat_getcwd(char *buffer, int maxlen)
{
    return getcwd(buffer, maxlen);
}

const char* plat_gettmpdir()
{
    static char s_tmpdir[PATH_MAX];

    if (!s_tmpdir[0])
    {
        const char *tmpdir = getenv("TMPDIR");

        if (!tmpdir)
        {
            tmpdir = P_tmpdir;
            if (!tmpdir)
                tmpdir = _PATH_TMP;
        }

        strncpy(s_tmpdir, tmpdir, sizeof(s_tmpdir));
        s_tmpdir[sizeof(s_tmpdir) - 1] = 0;

        // Remove trailing slash.
        size_t slen = strlen(s_tmpdir);
        if ((slen > 0) && (s_tmpdir[slen - 1] == '/'))
            s_tmpdir[--slen] = 0;
    }

    return s_tmpdir;
}

char* plat_gettmpfname(char *buffer, int maxlen, const char *prefix)
{
    const char *tmpdir = plat_gettmpdir();
    vogl::uint32 rnd32 = plat_rand();
    unsigned int time32 = time(NULL);

    snprintf(buffer, maxlen, "%s/_%s_%08x_%08x.tmp", tmpdir, prefix, time32, rnd32);
    buffer[maxlen - 1] = 0;
    return buffer;
}

// Tests for the existence of the specified path, returns true if it exists and false otherwise.
bool plat_fexist(const char* path)
{
    return access(path, F_OK) == 0;
}

pid_t plat_gettid()
{
    return static_cast<pid_t>(syscall(SYS_gettid));
}

uint64_t plat_posix_gettid()
{
    return static_cast<uint64_t>(pthread_self());
}

pid_t plat_getpid()
{
    return getpid();
}

pid_t plat_getppid()
{
    return getppid();
}

size_t plat_rand_s(vogl::uint32* out_array, size_t out_array_length)
{
    static __thread unsigned int s_seed = time(NULL);

    for (size_t i = 0; i < out_array_length; ++i)
        out_array[i] = rand_r(&s_seed);

    return out_array_length;
}

vogl::uint32 plat_rand()
{
    vogl::uint32 num;
    plat_rand_s(&num, 1);
    return num;
}

// Returns the size of a virtual page of memory.
vogl::int32 plat_get_virtual_page_size()
{
    return sysconf(_SC_PAGE_SIZE);
}

static int get_prot_from_access(vogl::uint32 access_flags)
{
    int ret_flags = 0;
    if ((access_flags & PLAT_WRITE) == PLAT_WRITE)
    {
        ret_flags |= PROT_WRITE;
        access_flags &= ~PLAT_WRITE;
    }

    if ((access_flags & (PLAT_READ)) == (PLAT_READ))
    {
        ret_flags |= PROT_READ;
        access_flags &= ~(PLAT_READ);
    }

    // If this fires, it means the code above needs to be updated to support the flag being passed in.
    VOGL_VERIFY(access_flags == 0);

    return ret_flags;
}

void* plat_virtual_alloc(size_t size_requested, vogl::uint32 access_flags, size_t* out_size_provided)
{
    const int prot = get_prot_from_access(access_flags);
    const int flags = MAP_ANON | MAP_SHARED;
    void *p = mmap(NULL, size_requested, prot, flags, -1, 0);

    if ((!p) || (p == MAP_FAILED))
    {
        uint e = errno;

        // Not using strerror_r because it fails when we're completely out of memory.
        char *pError_desc = strerror(e);

        char buf[256];
        sprintf(buf, "%s: mmap() of %zu bytes failed! Reason: %s (errno 0x%x)\n", VOGL_FUNCTION_NAME, size_requested, pError_desc, e);

        write(STDERR_FILENO, buf, strlen(buf));
        abort();
    }

    *out_size_provided = size_requested;

    return p;
}

void plat_virtual_free(void* free_addr, size_t size)
{
    int res = munmap(free_addr, size);
    if (res != 0)
    {
        uint e = errno;

        // Not using strerror_r because it fails when we're completely out of memory.
        char *pError_desc = strerror(e);

        char buf[256];
        sprintf(buf, "%s: munmap() free_addr 0x%" PRIxPTR " size 0x%" PRIxPTR " failed! Reason: %s (errno 0x%x)\n", VOGL_FUNCTION_NAME, (uintptr_t)free_addr, size, pError_desc, e);

        write(STDERR_FILENO, buf, strlen(buf));
        abort();
    }
}

#if VOGL_USE_PTHREADS_API
    int plat_sem_post(sem_t* sem, vogl::uint32 release_count)
    {
        int status = 0;
        while (release_count > 0)
        {
            status = sem_post(sem);
            if (status)
                break;
            release_count--;
        }

        return status;
    }

    void plat_try_sem_post(sem_t* sem, vogl::uint32 release_count)
    {
        while (release_count > 0)
        {
            sem_post(sem);
            release_count--;
        }
    }
#endif

void* plat_dlsym(void* handle, const char* symbol)
{
    return dlsym(handle, symbol);
}

<commit_msg>Seed plat_rand_s with dev/urandom, add tid and usec to tmpfname.<commit_after>/**************************************************************************
 *
 * Copyright 2013-2014 RAD Game Tools and Valve Software
 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

// File: vogl_port_posix.cpp

#if !defined(PLATFORM_POSIX)
    #error "vogl_port_posix should not be compiled on non-POSIX platforms."
#endif

#include "vogl_port.h"
#include <dlfcn.h>
#include <fcntl.h>
#include <paths.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/time.h>

int plat_chdir(const char* path)
{
    return chdir(path);
}

char* plat_getcwd(char *buffer, int maxlen)
{
    return getcwd(buffer, maxlen);
}

const char* plat_gettmpdir()
{
    static char s_tmpdir[PATH_MAX];

    if (!s_tmpdir[0])
    {
        const char *tmpdir = getenv("TMPDIR");

        if (!tmpdir)
        {
            tmpdir = P_tmpdir;
            if (!tmpdir)
                tmpdir = _PATH_TMP;
        }

        strncpy(s_tmpdir, tmpdir, sizeof(s_tmpdir));
        s_tmpdir[sizeof(s_tmpdir) - 1] = 0;

        // Remove trailing slash.
        size_t slen = strlen(s_tmpdir);
        if ((slen > 0) && (s_tmpdir[slen - 1] == '/'))
            s_tmpdir[--slen] = 0;
    }

    return s_tmpdir;
}

char* plat_gettmpfname(char *buffer, int maxlen, const char *prefix)
{
    struct timeval cur_time;
    vogl::uint32 rnd32 = plat_rand();
    const char *tmpdir = plat_gettmpdir();

    gettimeofday(&cur_time, NULL);

    uint64_t time64 = cur_time.tv_sec * 1000000ULL + cur_time.tv_usec;

    // Create a fileiname with THREADID & RAND32 & TIME64.
    snprintf(buffer, maxlen, "%s/_%s_%x_%x_%" PRIx64 ".tmp", tmpdir, prefix, plat_gettid(), rnd32, time64);
    buffer[maxlen - 1] = 0;
    return buffer;
}

// Tests for the existence of the specified path, returns true if it exists and false otherwise.
bool plat_fexist(const char* path)
{
    return access(path, F_OK) == 0;
}

pid_t plat_gettid()
{
    return static_cast<pid_t>(syscall(SYS_gettid));
}

uint64_t plat_posix_gettid()
{
    return static_cast<uint64_t>(pthread_self());
}

pid_t plat_getpid()
{
    return getpid();
}

pid_t plat_getppid()
{
    return getppid();
}

size_t plat_rand_s(vogl::uint32* out_array, size_t out_array_length)
{
    static __thread unsigned int s_seed = 0;

    if (s_seed == 0)
    {
        // Try to seed rand_r() with /dev/urandom.
        ssize_t nbytes = 0;
        int fd = open("/dev/urandom", O_RDONLY);
        if (fd != -1)
        {
            nbytes = read(fd, &s_seed, sizeof(s_seed));
            close(fd);
        }

        // If that didn't work, fallback to time and thread id.
        if (nbytes != sizeof(s_seed))
        {
            struct timeval time;
            gettimeofday(&time, NULL);
            s_seed = plat_gettid() ^ ((time.tv_sec * 1000) + (time.tv_usec / 1000));
        }
    }

    for (size_t i = 0; i < out_array_length; ++i)
        out_array[i] = rand_r(&s_seed);

    return out_array_length;
}

vogl::uint32 plat_rand()
{
    vogl::uint32 num;
    plat_rand_s(&num, 1);
    return num;
}

// Returns the size of a virtual page of memory.
vogl::int32 plat_get_virtual_page_size()
{
    return sysconf(_SC_PAGE_SIZE);
}

static int get_prot_from_access(vogl::uint32 access_flags)
{
    int ret_flags = 0;
    if ((access_flags & PLAT_WRITE) == PLAT_WRITE)
    {
        ret_flags |= PROT_WRITE;
        access_flags &= ~PLAT_WRITE;
    }

    if ((access_flags & (PLAT_READ)) == (PLAT_READ))
    {
        ret_flags |= PROT_READ;
        access_flags &= ~(PLAT_READ);
    }

    // If this fires, it means the code above needs to be updated to support the flag being passed in.
    VOGL_VERIFY(access_flags == 0);

    return ret_flags;
}

void* plat_virtual_alloc(size_t size_requested, vogl::uint32 access_flags, size_t* out_size_provided)
{
    const int prot = get_prot_from_access(access_flags);
    const int flags = MAP_ANON | MAP_SHARED;
    void *p = mmap(NULL, size_requested, prot, flags, -1, 0);

    if ((!p) || (p == MAP_FAILED))
    {
        uint e = errno;

        // Not using strerror_r because it fails when we're completely out of memory.
        char *pError_desc = strerror(e);

        char buf[256];
        sprintf(buf, "%s: mmap() of %zu bytes failed! Reason: %s (errno 0x%x)\n", VOGL_FUNCTION_NAME, size_requested, pError_desc, e);

        write(STDERR_FILENO, buf, strlen(buf));
        abort();
    }

    *out_size_provided = size_requested;

    return p;
}

void plat_virtual_free(void* free_addr, size_t size)
{
    int res = munmap(free_addr, size);
    if (res != 0)
    {
        uint e = errno;

        // Not using strerror_r because it fails when we're completely out of memory.
        char *pError_desc = strerror(e);

        char buf[256];
        sprintf(buf, "%s: munmap() free_addr 0x%" PRIxPTR " size 0x%" PRIxPTR " failed! Reason: %s (errno 0x%x)\n", VOGL_FUNCTION_NAME, (uintptr_t)free_addr, size, pError_desc, e);

        write(STDERR_FILENO, buf, strlen(buf));
        abort();
    }
}

#if VOGL_USE_PTHREADS_API
    int plat_sem_post(sem_t* sem, vogl::uint32 release_count)
    {
        int status = 0;
        while (release_count > 0)
        {
            status = sem_post(sem);
            if (status)
                break;
            release_count--;
        }

        return status;
    }

    void plat_try_sem_post(sem_t* sem, vogl::uint32 release_count)
    {
        while (release_count > 0)
        {
            sem_post(sem);
            release_count--;
        }
    }
#endif

void* plat_dlsym(void* handle, const char* symbol)
{
    return dlsym(handle, symbol);
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/expression.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/expression_node_types.hpp>
#include <mapnik/expression_grammar_x3.hpp>

namespace mapnik
{

expression_ptr parse_expression(std::string const& str)
{
    auto node = std::make_shared<expr_node>();
    using boost::spirit::x3::ascii::space;
    mapnik::transcoder const tr("utf8");
    auto parser = boost::spirit::x3::with<mapnik::grammar::transcoder_tag>(std::ref(tr))
        [
            mapnik::expression_grammar()
        ];

    bool r = false;
    std::string::const_iterator itr = str.begin();
    std::string::const_iterator const end = str.end();

    try
    {
        r = boost::spirit::x3::phrase_parse(itr, end, parser, space, *node);
    }
    catch (boost::spirit::x3::expectation_failure<std::string::const_iterator> const& ex)
    {
        // no need to show "boost::spirit::qi::expectation_failure" which is a std::runtime_error
        throw config_error("Failed to parse expression: \"" + str + "\"");
    }
    catch (std::exception const& ex)
    {
        // show "Could not initialize ICU resources" from boost::regex which is a std::runtime_error
        throw config_error(std::string(ex.what()) + " for expression: \"" + str + "\"");
    }
    if (r && itr == end)
    {
        return node;
    }
    else
    {
        throw config_error("Failed to parse expression: \"" + str + "\"");
    }
}

}
<commit_msg>update comment<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/expression.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/expression_node_types.hpp>
#include <mapnik/expression_grammar_x3.hpp>

namespace mapnik
{

expression_ptr parse_expression(std::string const& str)
{
    auto node = std::make_shared<expr_node>();
    using boost::spirit::x3::ascii::space;
    mapnik::transcoder const tr("utf8");
    auto parser = boost::spirit::x3::with<mapnik::grammar::transcoder_tag>(std::ref(tr))
        [
            mapnik::expression_grammar()
        ];

    bool r = false;
    std::string::const_iterator itr = str.begin();
    std::string::const_iterator const end = str.end();

    try
    {
        r = boost::spirit::x3::phrase_parse(itr, end, parser, space, *node);
    }
    catch (boost::spirit::x3::expectation_failure<std::string::const_iterator> const& ex)
    {
        // no need to show "boost::spirit::x3::expectation_failure" which is a std::runtime_error
        throw config_error("Failed to parse expression: \"" + str + "\"");
    }
    catch (std::exception const& ex)
    {
        // show "Could not initialize ICU resources" from boost::regex which is a std::runtime_error
        throw config_error(std::string(ex.what()) + " for expression: \"" + str + "\"");
    }
    if (r && itr == end)
    {
        return node;
    }
    else
    {
        throw config_error("Failed to parse expression: \"" + str + "\"");
    }
}

}
<|endoftext|>


<commit_before>#include "fetch/http.hpp"
#include "vector_tile.pb.h"

#include <boost/format.hpp>
#include <boost/algorithm/string/find_format.hpp>
#include <boost/xpressive/xpressive.hpp>

#include <sstream>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>

#include <curl/curl.h>

namespace avecado { namespace fetch {

namespace {

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) {
  std::stringstream *stream = static_cast<std::stringstream*>(userdata);
  size_t total_bytes = size * nmemb;
  stream->write(ptr, total_bytes);
  return stream->good() ? total_bytes : 0;
}

std::vector<std::string> singleton(const std::string &base_url, const std::string &ext) {
  std::vector<std::string> vec;
  vec.push_back((boost::format("%1%/{z}/{x}/{y}.%2%") % base_url % ext).str());
  return vec;
}

struct formatter {
  int z, x, y;

  formatter(int z_, int x_, int y_) : z(z_), x(x_), y(y_) {}

  template<typename Out>
  Out operator()(boost::xpressive::smatch const &what, Out out) const {
    int val = 0;

    char c = what[1].str()[0];
    if      (c == 'z') { val = z; }
    else if (c == 'x') { val = x; }
    else if (c == 'y') { val = y; }
    else { throw std::runtime_error("match failed"); }

    std::string sub = (boost::format("%1%") % val).str();
    out = std::copy(sub.begin(), sub.end(), out);

    return out;
  }
};

} // anonymous namespace

struct http::impl {
  impl(std::vector<std::string> &&patterns);

  fetch_response fetch(int z, int x, int y);

  std::string url_for(int z, int x, int y) const;

  std::vector<std::string> m_url_patterns;
};

http::impl::impl(std::vector<std::string> &&patterns)
  : m_url_patterns(patterns) {
}

fetch_response http::impl::fetch(int z, int x, int y) {
  std::string url = url_for(z, x, y);

  fetch_error err;
  err.status = fetch_status::server_error;
  fetch_response response(err);

  CURL *curl = curl_easy_init();
  if (curl != nullptr) {
    std::stringstream stream;

    CURLcode res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    if (res != CURLE_OK) { return response; }

    res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
    if (res != CURLE_OK) { return response; }

    res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream);
    if (res != CURLE_OK) { return response; }

    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
      if (res == CURLE_REMOTE_FILE_NOT_FOUND) {
        err.status = fetch_status::not_found;
      }
      response = fetch_response(err);

    } else {
      long status_code = 0;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);

      if (status_code == 200) {
        std::unique_ptr<tile> ptr(new tile);
        google::protobuf::io::IstreamInputStream gstream(&stream);
        if (!ptr->mapnik_tile().ParseFromZeroCopyStream(&gstream)) {
          return response;
        }
        response = fetch_response(std::move(ptr));

      } else {
        switch (status_code) {
        case 400: err.status = fetch_status::bad_request; break;
        case 404: err.status = fetch_status::not_found; break;
        case 501: err.status = fetch_status::not_implemented; break;
        default:
          err.status = fetch_status::server_error;
        }
        response = fetch_response(err);
      }
    }

    curl_easy_cleanup(curl);
  }

  return response;
}

std::string http::impl::url_for(int z, int x, int y) const {
  using namespace boost::xpressive;

  if (m_url_patterns.empty()) {
    throw std::runtime_error("no URL patterns in fetcher");
  }

  sregex var = "{" >> (s1 = range('x','z')) >> "}";
  return regex_replace(m_url_patterns[0], var, formatter(z, x, y));
}

http::http(const std::string &base_url, const std::string &ext)
  : m_impl(new impl(singleton(base_url, ext))) {
}

http::http(std::vector<std::string> &&patterns)
  : m_impl(new impl(std::move(patterns))) {
}

http::~http() {
}

std::future<fetch_response> http::operator()(int z, int x, int y) {
  return std::async([this, z, x, y]() -> fetch_response { return m_impl->fetch(z, x, y); });
}

} } // namespace avecado::fetch
<commit_msg>Make fetch const, helps keep safe for multi-threaded access.<commit_after>#include "fetch/http.hpp"
#include "vector_tile.pb.h"

#include <boost/format.hpp>
#include <boost/algorithm/string/find_format.hpp>
#include <boost/xpressive/xpressive.hpp>

#include <sstream>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>

#include <curl/curl.h>

namespace avecado { namespace fetch {

namespace {

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) {
  std::stringstream *stream = static_cast<std::stringstream*>(userdata);
  size_t total_bytes = size * nmemb;
  stream->write(ptr, total_bytes);
  return stream->good() ? total_bytes : 0;
}

std::vector<std::string> singleton(const std::string &base_url, const std::string &ext) {
  std::vector<std::string> vec;
  vec.push_back((boost::format("%1%/{z}/{x}/{y}.%2%") % base_url % ext).str());
  return vec;
}

struct formatter {
  int z, x, y;

  formatter(int z_, int x_, int y_) : z(z_), x(x_), y(y_) {}

  template<typename Out>
  Out operator()(boost::xpressive::smatch const &what, Out out) const {
    int val = 0;

    char c = what[1].str()[0];
    if      (c == 'z') { val = z; }
    else if (c == 'x') { val = x; }
    else if (c == 'y') { val = y; }
    else { throw std::runtime_error("match failed"); }

    std::string sub = (boost::format("%1%") % val).str();
    out = std::copy(sub.begin(), sub.end(), out);

    return out;
  }
};

} // anonymous namespace

struct http::impl {
  impl(std::vector<std::string> &&patterns);

  fetch_response fetch(int z, int x, int y) const;

  std::string url_for(int z, int x, int y) const;

  std::vector<std::string> m_url_patterns;
};

http::impl::impl(std::vector<std::string> &&patterns)
  : m_url_patterns(patterns) {
}

fetch_response http::impl::fetch(int z, int x, int y) const {
  std::string url = url_for(z, x, y);

  fetch_error err;
  err.status = fetch_status::server_error;
  fetch_response response(err);

  CURL *curl = curl_easy_init();
  if (curl != nullptr) {
    std::stringstream stream;

    CURLcode res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    if (res != CURLE_OK) { return response; }

    res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
    if (res != CURLE_OK) { return response; }

    res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream);
    if (res != CURLE_OK) { return response; }

    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
      if (res == CURLE_REMOTE_FILE_NOT_FOUND) {
        err.status = fetch_status::not_found;
      }
      response = fetch_response(err);

    } else {
      long status_code = 0;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);

      if (status_code == 200) {
        std::unique_ptr<tile> ptr(new tile);
        google::protobuf::io::IstreamInputStream gstream(&stream);
        if (!ptr->mapnik_tile().ParseFromZeroCopyStream(&gstream)) {
          return response;
        }
        response = fetch_response(std::move(ptr));

      } else {
        switch (status_code) {
        case 400: err.status = fetch_status::bad_request; break;
        case 404: err.status = fetch_status::not_found; break;
        case 501: err.status = fetch_status::not_implemented; break;
        default:
          err.status = fetch_status::server_error;
        }
        response = fetch_response(err);
      }
    }

    curl_easy_cleanup(curl);
  }

  return response;
}

std::string http::impl::url_for(int z, int x, int y) const {
  using namespace boost::xpressive;

  if (m_url_patterns.empty()) {
    throw std::runtime_error("no URL patterns in fetcher");
  }

  sregex var = "{" >> (s1 = range('x','z')) >> "}";
  return regex_replace(m_url_patterns[0], var, formatter(z, x, y));
}

http::http(const std::string &base_url, const std::string &ext)
  : m_impl(new impl(singleton(base_url, ext))) {
}

http::http(std::vector<std::string> &&patterns)
  : m_impl(new impl(std::move(patterns))) {
}

http::~http() {
}

std::future<fetch_response> http::operator()(int z, int x, int y) {
  return std::async([this, z, x, y]() -> fetch_response { return m_impl->fetch(z, x, y); });
}

} } // namespace avecado::fetch
<|endoftext|>


<commit_before>#include "sim.h"

Sim::SubmissionPermissions Sim::submissions_get_permissions(
	StringView submission_owner, SubmissionType stype, ContestUserMode cu_mode,
	StringView problem_owner)
{
	using PERM = SubmissionPermissions;
	using STYPE = SubmissionType;
	using CUM = ContestUserMode;

	if (not session_open())
		return PERM::NONE;

	static_assert((uint)PERM::NONE == 0, "Needed below");
	PERM PERM_SUBMISSION_ADMIN = PERM::VIEW | PERM::VIEW_SOURCE |
		PERM::VIEW_FINAL_REPORT | PERM::VIEW_RELATED_JOBS | PERM::REJUDGE |
		(isIn(stype, {STYPE::NORMAL, STYPE::FINAL, STYPE::IGNORED})
			? PERM::CHANGE_TYPE | PERM::DELETE : PERM::NONE);

	if (session_user_type == UserType::ADMIN)
		return PERM::VIEW_ALL | PERM_SUBMISSION_ADMIN;

	if (cu_mode == CUM::MODERATOR or cu_mode == CUM::OWNER)
		return PERM_SUBMISSION_ADMIN;

	// This check has to be done as the last one because it gives the least
	// permissions
	if (session_user_id == problem_owner) {
		if (stype == STYPE::PROBLEM_SOLUTION)
			return PERM::VIEW | PERM::VIEW_SOURCE |	PERM::VIEW_RELATED_JOBS
				| PERM::REJUDGE;
		return PERM::VIEW | PERM::REJUDGE;
	}

	if (session_user_id == submission_owner)
		return PERM::VIEW | PERM::VIEW_SOURCE;

	return PERM::NONE;
}

void Sim::submissions_handle() {
	STACK_UNWINDING_MARK;

	StringView next_arg = url_args.extractNextArg();
	// View submission
	if (isDigit(next_arg)) {
		page_template(concat("Submission ", next_arg),
			"body{padding-left:20px}");
		append("");

	// List submissions
	} else if (next_arg.empty() and
		uint(submissions_get_permissions() & SubmissionPermissions::VIEW_ALL))
	{
		page_template("Submissions", "body{padding-left:20px}");
		append("
Submissions
"
			"");

	} else
		return error404();
}
<commit_msg>Fixed indentation<commit_after>#include "sim.h"

Sim::SubmissionPermissions Sim::submissions_get_permissions(
	StringView submission_owner, SubmissionType stype, ContestUserMode cu_mode,
	StringView problem_owner)
{
	using PERM = SubmissionPermissions;
	using STYPE = SubmissionType;
	using CUM = ContestUserMode;

	if (not session_open())
		return PERM::NONE;

	static_assert((uint)PERM::NONE == 0, "Needed below");
	PERM PERM_SUBMISSION_ADMIN = PERM::VIEW | PERM::VIEW_SOURCE |
		PERM::VIEW_FINAL_REPORT | PERM::VIEW_RELATED_JOBS | PERM::REJUDGE |
		(isIn(stype, {STYPE::NORMAL, STYPE::FINAL, STYPE::IGNORED})
			? PERM::CHANGE_TYPE | PERM::DELETE : PERM::NONE);

	if (session_user_type == UserType::ADMIN)
		return PERM::VIEW_ALL | PERM_SUBMISSION_ADMIN;

	if (cu_mode == CUM::MODERATOR or cu_mode == CUM::OWNER)
		return PERM_SUBMISSION_ADMIN;

	// This check has to be done as the last one because it gives the least
	// permissions
	if (session_user_id == problem_owner) {
		if (stype == STYPE::PROBLEM_SOLUTION)
			return PERM::VIEW | PERM::VIEW_SOURCE |	PERM::VIEW_RELATED_JOBS
				| PERM::REJUDGE;
		return PERM::VIEW | PERM::REJUDGE;
	}

	if (session_user_id == submission_owner)
		return PERM::VIEW | PERM::VIEW_SOURCE;

	return PERM::NONE;
}

void Sim::submissions_handle() {
	STACK_UNWINDING_MARK;

	StringView next_arg = url_args.extractNextArg();
	// View submission
	if (isDigit(next_arg)) {
		page_template(concat("Submission ", next_arg),
			"body{padding-left:20px}");
		append("");

	// List submissions
	} else if (next_arg.empty() and
		uint(submissions_get_permissions() & SubmissionPermissions::VIEW_ALL))
	{
		page_template("Submissions", "body{padding-left:20px}");
		append("
Submissions
"
			"");

	} else
		return error404();
}
<|endoftext|>


<commit_before>#include <iostream>

#include "texture.h"

#include "glm/glm.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/normal.hpp>

#include "../tools/fs.h"
#include "../loaders/pixels.h"

// TEXTURE
Texture::Texture():m_path(""), m_width(0), m_height(0), m_id(0) {
}

Texture::~Texture() {
    glDeleteTextures(1, &m_id);
}

bool Texture::load(const std::string& _path, bool _vFlip) {
    std::string ext = getExt(_path);

    // Generate an OpenGL texture ID for this texture
    glEnable(GL_TEXTURE_2D);
    if (m_id == 0)
        glGenTextures(1, &m_id);
    glBindTexture(GL_TEXTURE_2D, m_id);

    // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    if (ext == "png"    || ext == "PNG" ||
        ext == "jpg"    || ext == "JPG" ||
        ext == "jpeg"   || ext == "JPEG") {

        unsigned char* pixels = loadPixels(_path, &m_width, &m_height, RGB_ALPHA, _vFlip);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

        // delete[] pixels;
        delete pixels;
    }

    else if (ext == "hdr" || ext == "HDR") {
        float* pixels = loadHDRFloatPixels(_path, &m_width, &m_height, _vFlip);

    #if defined(PLATFORM_RPI) || defined(PLATFORM_RPI4)
        GLenum InternalFormat = GL_RGB;
    #else
        GLenum InternalFormat = GL_RGB16F_ARB;
    #endif

        glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, m_width, m_height, 0, GL_RGB, GL_FLOAT, pixels);

        // delete[] pixels;
        delete pixels;
    }

    glGenerateMipmap(GL_TEXTURE_2D);

    m_path = _path;

    unbind();

    return true;
}

bool Texture::loadBump(const std::string& _path, bool _vFlip) {
    std::string ext = getExt(_path);

    // Generate an OpenGL texture ID for this texture
    glEnable(GL_TEXTURE_2D);
    if (m_id == 0)
        glGenTextures(1, &m_id);
    glBindTexture(GL_TEXTURE_2D, m_id);

    // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    if (ext == "png"    || ext == "PNG" ||
        ext == "jpg"    || ext == "JPG" ||
        ext == "jpeg"   || ext == "JPEG") {

        uint16_t* pixels = loadPixels16(_path, &m_width, &m_height, LUMINANCE, _vFlip);

        const int n = m_width * m_height;
        const float m = 1.f / 65535.f;
        std::vector<float> data;
        data.resize(n);
        for (int i = 0; i < n; i++) {
            data[i] = pixels[i] * m;
        }

        float _scale = -10.0;

        const int w = m_width - 1;
        const int h = m_height - 1;
        std::vector<glm::vec3> result(w * h);
        int i = 0;
        for (int y0 = 0; y0 < h; y0++) {
            const int y1 = y0 + 1;
            const float yc = y0 + 0.5f;
            for (int x0 = 0; x0 < w; x0++) {
                const int x1 = x0 + 1;
                const float xc = x0 + 0.5f;
                const float z00 = data[y0 * w + x0] * -_scale;
                const float z01 = data[y1 * w + x0] * -_scale;
                const float z10 = data[y0 * w + x1] * -_scale;
                const float z11 = data[y1 * w + x1] * -_scale;
                const float zc = (z00 + z01 + z10 + z11) / 4.f;
                const glm::vec3 p00(x0, y0, z00);
                const glm::vec3 p01(x0, y1, z01);
                const glm::vec3 p10(x1, y0, z10);
                const glm::vec3 p11(x1, y1, z11);
                const glm::vec3 pc(xc, yc, zc);
                const glm::vec3 n0 = glm::triangleNormal(pc, p00, p10);
                const glm::vec3 n1 = glm::triangleNormal(pc, p10, p11);
                const glm::vec3 n2 = glm::triangleNormal(pc, p11, p01);
                const glm::vec3 n3 = glm::triangleNormal(pc, p01, p00);
                result[i] = glm::normalize(n0 + n1 + n2 + n3) * 0.5f + 0.5f;
                i++;
            }
        }

    #if defined(PLATFORM_RPI) || defined(PLATFORM_RPI4)
        GLenum InternalFormat = GL_RGB;
    #else
        GLenum InternalFormat = GL_RGB16F_ARB;
    #endif

        glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, m_width, m_height, 0, GL_RGB, GL_FLOAT, &result[0]);

        delete pixels;
    }

    glGenerateMipmap(GL_TEXTURE_2D);

    m_path = _path;

    unbind();

    return true;
}

bool Texture::load(int _width, int _height, int _component, int _bits, const unsigned char* _data) {

    // Generate an OpenGL texture ID for this texturez
    glEnable(GL_TEXTURE_2D);
    if (m_id == 0)
        glGenTextures(1, &m_id);
    glBindTexture(GL_TEXTURE_2D, m_id);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    GLenum format = GL_RGBA;
    if (_component == 1) {
        format = GL_RED;
    } else if (_component == 2) {
        format = GL_RG;
    } else if (_component == 3) {
        format = GL_RGB;
    } else {
      // ???
    }

    GLenum type = GL_UNSIGNED_BYTE;
    if (_bits == 8) {
        // ok
    } else if (_bits == 16) {
        type = GL_UNSIGNED_SHORT;
    } else {
        // ???
    }

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, format, type, _data);
    // glGenerateMipmap(GL_TEXTURE_2D);
    return true;
}

void Texture::bind() {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_id);
}

void Texture::unbind() {
    glBindTexture(GL_TEXTURE_2D, 0);
}
<commit_msg>ignoring non RGBA or RGB texture formats on raspberry pi<commit_after>#include <iostream>

#include "texture.h"

#include "glm/glm.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/normal.hpp>

#include "../tools/fs.h"
#include "../loaders/pixels.h"

// TEXTURE
Texture::Texture():m_path(""), m_width(0), m_height(0), m_id(0) {
}

Texture::~Texture() {
    glDeleteTextures(1, &m_id);
}

bool Texture::load(const std::string& _path, bool _vFlip) {
    std::string ext = getExt(_path);

    // Generate an OpenGL texture ID for this texture
    glEnable(GL_TEXTURE_2D);
    if (m_id == 0)
        glGenTextures(1, &m_id);
    glBindTexture(GL_TEXTURE_2D, m_id);

    // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    if (ext == "png"    || ext == "PNG" ||
        ext == "jpg"    || ext == "JPG" ||
        ext == "jpeg"   || ext == "JPEG") {

        unsigned char* pixels = loadPixels(_path, &m_width, &m_height, RGB_ALPHA, _vFlip);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

        // delete[] pixels;
        delete pixels;
    }

    else if (ext == "hdr" || ext == "HDR") {
        float* pixels = loadHDRFloatPixels(_path, &m_width, &m_height, _vFlip);

    #if defined(PLATFORM_RPI) || defined(PLATFORM_RPI4)
        GLenum InternalFormat = GL_RGB;
    #else
        GLenum InternalFormat = GL_RGB16F_ARB;
    #endif

        glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, m_width, m_height, 0, GL_RGB, GL_FLOAT, pixels);

        // delete[] pixels;
        delete pixels;
    }

    glGenerateMipmap(GL_TEXTURE_2D);

    m_path = _path;

    unbind();

    return true;
}

bool Texture::loadBump(const std::string& _path, bool _vFlip) {
    std::string ext = getExt(_path);

    // Generate an OpenGL texture ID for this texture
    glEnable(GL_TEXTURE_2D);
    if (m_id == 0)
        glGenTextures(1, &m_id);
    glBindTexture(GL_TEXTURE_2D, m_id);

    // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    if (ext == "png"    || ext == "PNG" ||
        ext == "jpg"    || ext == "JPG" ||
        ext == "jpeg"   || ext == "JPEG") {

        uint16_t* pixels = loadPixels16(_path, &m_width, &m_height, LUMINANCE, _vFlip);

        const int n = m_width * m_height;
        const float m = 1.f / 65535.f;
        std::vector<float> data;
        data.resize(n);
        for (int i = 0; i < n; i++) {
            data[i] = pixels[i] * m;
        }

        float _scale = -10.0;

        const int w = m_width - 1;
        const int h = m_height - 1;
        std::vector<glm::vec3> result(w * h);
        int i = 0;
        for (int y0 = 0; y0 < h; y0++) {
            const int y1 = y0 + 1;
            const float yc = y0 + 0.5f;
            for (int x0 = 0; x0 < w; x0++) {
                const int x1 = x0 + 1;
                const float xc = x0 + 0.5f;
                const float z00 = data[y0 * w + x0] * -_scale;
                const float z01 = data[y1 * w + x0] * -_scale;
                const float z10 = data[y0 * w + x1] * -_scale;
                const float z11 = data[y1 * w + x1] * -_scale;
                const float zc = (z00 + z01 + z10 + z11) / 4.f;
                const glm::vec3 p00(x0, y0, z00);
                const glm::vec3 p01(x0, y1, z01);
                const glm::vec3 p10(x1, y0, z10);
                const glm::vec3 p11(x1, y1, z11);
                const glm::vec3 pc(xc, yc, zc);
                const glm::vec3 n0 = glm::triangleNormal(pc, p00, p10);
                const glm::vec3 n1 = glm::triangleNormal(pc, p10, p11);
                const glm::vec3 n2 = glm::triangleNormal(pc, p11, p01);
                const glm::vec3 n3 = glm::triangleNormal(pc, p01, p00);
                result[i] = glm::normalize(n0 + n1 + n2 + n3) * 0.5f + 0.5f;
                i++;
            }
        }

    #if defined(PLATFORM_RPI) || defined(PLATFORM_RPI4)
        GLenum InternalFormat = GL_RGB;
    #else
        GLenum InternalFormat = GL_RGB16F_ARB;
    #endif

        glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, m_width, m_height, 0, GL_RGB, GL_FLOAT, &result[0]);

        delete pixels;
    }

    glGenerateMipmap(GL_TEXTURE_2D);

    m_path = _path;

    unbind();

    return true;
}

bool Texture::load(int _width, int _height, int _component, int _bits, const unsigned char* _data) {

    // Generate an OpenGL texture ID for this texturez
    glEnable(GL_TEXTURE_2D);
    if (m_id == 0)
        glGenTextures(1, &m_id);
    glBindTexture(GL_TEXTURE_2D, m_id);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    GLenum format = GL_RGBA;
    if (_component == 3) {
        format = GL_RGB;
    }
#if !defined(PLATFORM_RPI) && !defined(PLATFORM_RPI4)
    else if (_component == 1) {
        format = GL_RED;
    }
    else if (_component == 2) {
        format = GL_RG;
    }
#endif
    else
        std::cout << "Unrecognize GLenum format " << _component << std::endl;

    GLenum type = GL_UNSIGNED_BYTE;
    if (_bits == 8) {
        // ok
    }
    else if (_bits == 16) {
        type = GL_UNSIGNED_SHORT;
    }
    else
        std::cout << "Unrecognize GLenum type for " << _bits << " bits" << std::endl;

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, format, type, _data);
    // glGenerateMipmap(GL_TEXTURE_2D);
    return true;
}

void Texture::bind() {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_id);
}

void Texture::unbind() {
    glBindTexture(GL_TEXTURE_2D, 0);
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_MAT_FUN_LOG1P_HPP
#define STAN_MATH_PRIM_MAT_FUN_LOG1P_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/vectorize/apply_scalar_unary.hpp>
#include <stan/math/prim/scal/fun/log1p.hpp>

namespace stan {
namespace math {

/**
 * Structure to wrap log1p() so it can be vectorized.
 */
struct log1p_fun {
  /**
   * Return the inverse hypberbolic cosine of the specified argument.
   *
   * @param x Argument.
   * @return Inverse hyperbolic cosine of the argument.
   * @tparam T Argument type.
   */
  template <typename T>
  static inline T fun(const T& x) {
    return log1p(x);
  }
};

/**
 * Return the elementwise application of log1p() to
 * specified argument container.  The return type promotes the
 * underlying scalar argument type to double if it is an integer,
 * and otherwise is the argument type.
 *
 * @tparam T Container type.
 * @param x Container.
 * @return Elementwise log1p of members of container.
 */
template <
    typename T /*, typename = require_not_eigen_vt<std::is_arithmetic, T>*/>
inline auto log1p(const T& x) {
  return apply_scalar_unary<log1p_fun, T>::apply(x);
}

// TODO(Tadej): This is inconsistent with stan's scalar version (which throws on
// value <-1).
///**
// * Version of log1p() that accepts Eigen Matrix ar matrix expressions.
// * @tparam Derived derived type of x
// * @param x Matrix or matrix expression
// * @return Elementwise log1p of members of container.
// */
// template <typename Derived, typename = require_eigen_vt<std::is_arithmetic,
// Derived>>  inline auto log1p(const Eigen::MatrixBase<Derived>& x){
//  return x.derived().array().log1p().matrix();
//}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>deleted commented code<commit_after>#ifndef STAN_MATH_PRIM_MAT_FUN_LOG1P_HPP
#define STAN_MATH_PRIM_MAT_FUN_LOG1P_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/vectorize/apply_scalar_unary.hpp>
#include <stan/math/prim/scal/fun/log1p.hpp>

namespace stan {
namespace math {

/**
 * Structure to wrap log1p() so it can be vectorized.
 */
struct log1p_fun {
  /**
   * Return the inverse hypberbolic cosine of the specified argument.
   *
   * @param x Argument.
   * @return Inverse hyperbolic cosine of the argument.
   * @tparam T Argument type.
   */
  template <typename T>
  static inline T fun(const T& x) {
    return log1p(x);
  }
};

/**
 * Return the elementwise application of log1p() to
 * specified argument container.  The return type promotes the
 * underlying scalar argument type to double if it is an integer,
 * and otherwise is the argument type.
 *
 * @tparam T Container type.
 * @param x Container.
 * @return Elementwise log1p of members of container.
 */
template <typename T>
inline auto log1p(const T& x) {
  return apply_scalar_unary<log1p_fun, T>::apply(x);
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>///
/// @file  D1.cpp
/// @brief Simple demonstration implementation of the D(x, y) formula
///        in Xavier Gourdon's prime counting algorithm. This
///        implementation runs single threaded and does not use the
///        highly optimized Sieve.cpp.
///
///        The D formula corresponds to the computation of the hard
///        special leaves (those that require use of a sieve) in the
///        Lagarias-Miller-Odlyzko and Deleglise-Rivat prime counting
///        algorithms.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <gourdon.hpp>
#include <primecount-internal.hpp>
#include <generate.hpp>
#include <min.hpp>
#include <imath.hpp>
#include <print.hpp>

#include <stdint.h>
#include <vector>

using namespace std;

namespace primecount {

int64_t D(int64_t x,
          int64_t y,
          int64_t z,
          int64_t k)
{
  print("");
  print("=== D(x, y) ===");
  print_gourdon(x, y, z, k, 1);

  double time = get_time();
  int64_t sum = 0;
  int64_t limit = x / z + 1;
  int64_t segment_size = isqrt(limit);
  int64_t x_star = get_x_star_gourdon(x, y);

  auto pi = generate_pi(x_star);
  auto primes = generate_primes<int32_t>(x_star);
  auto mu = generate_moebius(z);
  auto lpf = generate_lpf(z);
  auto mpf = generate_mpf(z);

  vector<char> sieve(segment_size);
  vector<int64_t> next(primes.begin(), primes.end());
  vector<int64_t> phi(primes.size(), 0);
  int64_t pi_x_star = pi[x_star];

  // segmented sieve of Eratosthenes
  for (int64_t low = 1; low < limit; low += segment_size)
  {
    // Current segment [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = 1;

    // Reset the sieve array
    fill(sieve.begin(), sieve.end(), 1);

    // Pre-sieve multiples of first k primes
    for (; b <= k; b++)
    {
      int64_t j = next[b];
      for (int64_t prime = primes[b]; j < high; j += prime)
        sieve[j - low] = 0;
      next[b] = j;
    }

    int64_t count_low_high = 0;
    for (int64_t i = low; i < high; i++)
      count_low_high += sieve[i - low];

    // For k + 1 <= b <= pi_x_star
    // Find all special leaves: n = primes[b] * m
    // In the interval: low <= (x / n) < high
    // Which satisfy:  mu[m] != 0 && lpf[m] > primes[b] && mpf[m] <= y
    for (; b <= pi_x_star; b++)
    {
      int64_t prime = primes[b];
      int64_t max_m = min3(x / (prime * low), x / ipow(prime, 3), z);
      int64_t min_m = max3(x / (prime * high), z / prime, prime);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= max_m)
        break;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 &&
            lpf[m] > prime &&
            mpf[m] <= y)
        {
          // We have found a special leaf. Compute it's contribution
          // phi(x / (primes[b] * m), b - 1) by counting the number
          // of unsieved elements <= x / (primes[b] * m) after having
          // removed the multiples of the first b - 1 primes.
          int64_t xpm = x / (prime * m);
          int64_t stop = xpm - low;
          for (; i <= stop; i++)
            count += sieve[i];
          int64_t phi_xpm = phi[b] + count;
          sum -= mu[m] * phi_xpm;
        }
      }

      phi[b] += count_low_high;

      // Remove the multiples of the b-th prime
      int64_t j = next[b];
      for (; j < high; j += prime * 2)
      {
        count_low_high -= sieve[j - low];
        sieve[j - low] = 0;
      }
      next[b] = j;
    }
  }

  print("D", sum, time);
  return sum;
}

} // namespace
<commit_msg>Fix array out of bounds<commit_after>///
/// @file  D1.cpp
/// @brief Simple demonstration implementation of the D(x, y) formula
///        in Xavier Gourdon's prime counting algorithm. This
///        implementation runs single threaded and does not use the
///        highly optimized Sieve.cpp.
///
///        The D formula corresponds to the computation of the hard
///        special leaves (those that require use of a sieve) in the
///        Lagarias-Miller-Odlyzko and Deleglise-Rivat prime counting
///        algorithms.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <gourdon.hpp>
#include <primecount-internal.hpp>
#include <generate.hpp>
#include <min.hpp>
#include <imath.hpp>
#include <print.hpp>

#include <stdint.h>
#include <vector>

using namespace std;

namespace primecount {

int64_t D(int64_t x,
          int64_t y,
          int64_t z,
          int64_t k)
{
  print("");
  print("=== D(x, y) ===");
  print_gourdon(x, y, z, k, 1);

  double time = get_time();
  int64_t sum = 0;
  int64_t limit = x / z + 1;
  int64_t segment_size = isqrt(limit);
  int64_t x_star = get_x_star_gourdon(x, y);

  auto pi = generate_pi(x_star);
  auto primes = generate_primes<int32_t>(x_star);
  auto mu = generate_moebius(z);
  auto lpf = generate_lpf(z);
  auto mpf = generate_mpf(z);

  vector<char> sieve(segment_size);
  vector<int64_t> next(primes.begin(), primes.end());
  vector<int64_t> phi(primes.size(), 0);
  int64_t pi_x_star = pi[x_star];

  // segmented sieve of Eratosthenes
  for (int64_t low = 1; low < limit; low += segment_size)
  {
    // Current segment [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = 1;

    // Reset the sieve array
    fill(sieve.begin(), sieve.end(), 1);

    // Pre-sieve multiples of first k primes
    for (; b <= min(k, pi_x_star); b++)
    {
      int64_t j = next[b];
      for (int64_t prime = primes[b]; j < high; j += prime)
        sieve[j - low] = 0;
      next[b] = j;
    }

    int64_t count_low_high = 0;
    for (int64_t i = low; i < high; i++)
      count_low_high += sieve[i - low];

    // For k + 1 <= b <= pi_x_star
    // Find all special leaves: n = primes[b] * m
    // In the interval: low <= (x / n) < high
    // Which satisfy:  mu[m] != 0 && lpf[m] > primes[b] && mpf[m] <= y
    for (; b <= pi_x_star; b++)
    {
      int64_t prime = primes[b];
      int64_t max_m = min3(x / (prime * low), x / ipow(prime, 3), z);
      int64_t min_m = max3(x / (prime * high), z / prime, prime);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= max_m)
        break;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 &&
            lpf[m] > prime &&
            mpf[m] <= y)
        {
          // We have found a special leaf. Compute it's contribution
          // phi(x / (primes[b] * m), b - 1) by counting the number
          // of unsieved elements <= x / (primes[b] * m) after having
          // removed the multiples of the first b - 1 primes.
          int64_t xpm = x / (prime * m);
          int64_t stop = xpm - low;
          for (; i <= stop; i++)
            count += sieve[i];
          int64_t phi_xpm = phi[b] + count;
          sum -= mu[m] * phi_xpm;
        }
      }

      phi[b] += count_low_high;

      // Remove the multiples of the b-th prime
      int64_t j = next[b];
      for (; j < high; j += prime * 2)
      {
        count_low_high -= sieve[j - low];
        sieve[j - low] = 0;
      }
      next[b] = j;
    }
  }

  print("D", sum, time);
  return sum;
}

} // namespace
<|endoftext|>


<commit_before>/* ------------------------------------------------------------------------ */
/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)           */
/*                                                                          */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may  */
/* not use this file except in compliance with the License. You may obtain  */
/* a copy of the License at                                                 */
/*                                                                          */
/* http://www.apache.org/licenses/LICENSE-2.0                               */
/*                                                                          */
/* Unless required by applicable law or agreed to in writing, software      */
/* distributed under the License is distributed on an "AS IS" BASIS,        */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and      */
/* limitations under the License.                                           */
/* ------------------------------------------------------------------------ */

#include <limits.h>
#include <string.h>

#include <iostream>
#include <sstream>
#include <openssl/evp.h>
#include <iomanip>

#include "Image.h"
#include "ImagePool.h"

#include "AuthManager.h"
#include "UserPool.h"

#define TO_UPPER(S) transform(S.begin(),S.end(),S.begin(),(int(*)(int))toupper)

/* ************************************************************************ */
/* Image :: Constructor/Destructor                                          */
/* ************************************************************************ */

Image::Image(int             _uid,
             const string&   _user_name,
             ImageTemplate * _image_template):
        PoolObjectSQL(-1,"",_uid,table),
        user_name(_user_name),
        type(OS),
        regtime(time(0)),
        source(""),
        state(INIT),
        running_vms(0)
{
    if (_image_template != 0)
    {
        obj_template = _image_template;
    }
    else
    {
        obj_template = new ImageTemplate;
    }
}

Image::~Image()
{
    if (obj_template != 0)
    {
        delete obj_template;
    }
}

/* ************************************************************************ */
/* Image :: Database Access Functions                                       */
/* ************************************************************************ */

const char * Image::table = "image_pool";

const char * Image::db_names = "oid, name, body, uid, public";

const char * Image::db_bootstrap = "CREATE TABLE IF NOT EXISTS image_pool ("
    "oid INTEGER PRIMARY KEY, name VARCHAR(256), body TEXT, uid INTEGER, "
    "public INTEGER, UNIQUE(name,uid) )";

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

string Image::generate_source(int uid, const string& name)
{
    ostringstream tmp_hashstream;
    ostringstream tmp_sourcestream;

    tmp_hashstream << uid << ":" << name;

    tmp_sourcestream << ImagePool::source_prefix() << "/";
    tmp_sourcestream << sha1_digest(tmp_hashstream.str());

    return tmp_sourcestream.str();
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::insert(SqlDB *db, string& error_str)
{
    int rc;

    string path_attr;
    string type_att;
    string public_attr;
    string persistent_attr;
    string dev_prefix;

    // ---------------------------------------------------------------------
    // Check default image attributes
    // ---------------------------------------------------------------------

    // ------------ NAME --------------------

    get_template_attribute("NAME", name);

    // ------------ TYPE --------------------

    get_template_attribute("TYPE", type_att);

    TO_UPPER(type_att);

    if ( type_att.empty() == true )
    {
        type_att = ImagePool::default_type();
    }

    if (set_type(type_att) != 0)
    {
        goto error_type;
    }

    // ------------ PUBLIC --------------------

    get_template_attribute("PUBLIC", public_attr);

    obj_template->erase("PUBLIC");

    TO_UPPER(public_attr);

    public_img = (public_attr == "YES");

    // ------------ PERSISTENT --------------------

    get_template_attribute("PERSISTENT", persistent_attr);

    obj_template->erase("PERSISTENT");

    TO_UPPER(persistent_attr);

    persistent_img = (persistent_attr == "YES");

    // An image cannot be public and persistent simultaneously

    if ( public_img && persistent_img )
    {
        goto error_public_and_persistent;
    }

    // ------------ PREFIX --------------------

    get_template_attribute("DEV_PREFIX", dev_prefix);

    if( dev_prefix.empty() )
    {
        SingleAttribute * dev_att = new SingleAttribute("DEV_PREFIX",
                                          ImagePool::default_dev_prefix());
        obj_template->set(dev_att);
    }

    // ------------ PATH & SOURCE --------------------

    get_template_attribute("PATH", path_attr);
    get_template_attribute("SOURCE", source);

    // The template should contain PATH or SOURCE
    if ( source.empty() && path_attr.empty() )
    {
        string size_attr;
        string fstype_attr;

        istringstream iss;
        int size_mb;

        get_template_attribute("SIZE",   size_attr);
        get_template_attribute("FSTYPE", fstype_attr);

        // DATABLOCK image needs SIZE and FSTYPE
        if (type != DATABLOCK || size_attr.empty() || fstype_attr.empty())
        {
            goto error_no_path;
        }

        iss.str(size_attr);

        iss >> size_mb;

        if (iss.fail() == true)
        {
            goto error_size_format;
        }
    }
    else if ( !source.empty() && !path_attr.empty() )
    {
        goto error_path_and_source;
    }

    if (source.empty())
    {
        source = Image::generate_source(uid,name);
    }

    state = LOCKED; //LOCKED till the ImageManager copies it to the Repository

    //--------------------------------------------------------------------------
    // Insert the Image
    //--------------------------------------------------------------------------

    rc = insert_replace(db, false);

    if ( rc == -1 )
    {
        error_str = "Error inserting Image in DB.";
    }

    return rc;

error_type:
    error_str = "Incorrect TYPE in template.";
    goto error_common;

error_public_and_persistent:
    error_str = "Image cannot be public and persistent.";
    goto error_common;

error_no_path:
    if ( type == DATABLOCK )
    {
        error_str = "A DATABLOCK type IMAGE has to declare a PATH, or both "
                    "SIZE and FSTYPE.";
    }
    else
    {
        error_str = "No PATH in template.";
    }
    goto error_common;

error_size_format:
    error_str = "Wrong number in SIZE.";
    goto error_common;

error_path_and_source:
    error_str = "Template malformed, PATH and SOURCE are mutuallly exclusive.";
    goto error_common;

error_common:
    NebulaLog::log("IMG", Log::ERROR, error_str);
    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::update(SqlDB *db)
{
    return insert_replace(db, true);;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::insert_replace(SqlDB *db, bool replace)
{
    ostringstream   oss;

    int    rc;

    string xml_body;

    char * sql_name;
    char * sql_xml;

    // Update the Image

    sql_name = db->escape_str(name.c_str());

    if ( sql_name == 0 )
    {
        goto error_name;
    }

    sql_xml = db->escape_str(to_xml(xml_body).c_str());

    if ( sql_xml == 0 )
    {
        goto error_body;
    }

    if(replace)
    {
        oss << "REPLACE";
    }
    else
    {
        oss << "INSERT";
    }

    // Construct the SQL statement to Insert or Replace

    oss <<" INTO "<< table <<" ("<< db_names <<") VALUES ("
        <<          oid             << ","
        << "'" <<   sql_name        << "',"
        << "'" <<   sql_xml         << "',"
        <<          uid             << ","
        <<          public_img      << ")";

    rc = db->exec(oss);

    db->free_str(sql_name);
    db->free_str(sql_xml);

    return rc;

error_body:
    db->free_str(sql_name);
error_name:
    return -1;
}

/* ************************************************************************ */
/* Image :: Misc                                                             */
/* ************************************************************************ */

ostream& operator<<(ostream& os, Image& image)
{
    string image_str;

    os << image.to_xml(image_str);

    return os;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

string& Image::to_xml(string& xml) const
{
    string template_xml;
    ostringstream   oss;

    oss <<
        "<IMAGE>" <<
            "<ID>"             << oid             << "</ID>"          <<
            "<UID>"            << uid             << "</UID>"         <<
            "<USERNAME>"       << user_name       << "</USERNAME>"    <<
            "<NAME>"           << name            << "</NAME>"        <<
            "<TYPE>"           << type            << "</TYPE>"        <<
            "<PUBLIC>"         << public_img      << "</PUBLIC>"      <<
            "<PERSISTENT>"     << persistent_img  << "</PERSISTENT>"  <<
            "<REGTIME>"        << regtime         << "</REGTIME>"     <<
            "<SOURCE>"         << source          << "</SOURCE>"      <<
            "<STATE>"          << state           << "</STATE>"       <<
            "<RUNNING_VMS>"    << running_vms     << "</RUNNING_VMS>" <<
            obj_template->to_xml(template_xml)                      <<
        "</IMAGE>";

    xml = oss.str();

    return xml;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::from_xml(const string& xml)
{
    vector<xmlNodePtr> content;
    int int_state;
    int int_type;

    int rc = 0;

    // Initialize the internal XML object
    update_from_str(xml);

    // Get class base attributes
    rc += xpath(oid, "/IMAGE/ID", -1);
    rc += xpath(uid, "/IMAGE/UID", -1);
    rc += xpath(user_name, "/IMAGE/USERNAME", "not_found");
    rc += xpath(name, "/IMAGE/NAME", "not_found");

    rc += xpath(int_type, "/IMAGE/TYPE", 0);
    rc += xpath(public_img, "/IMAGE/PUBLIC", 0);
    rc += xpath(persistent_img, "/IMAGE/PERSISTENT", 0);
    rc += xpath(regtime, "/IMAGE/REGTIME", 0);

    rc += xpath(source, "/IMAGE/SOURCE", "not_found");
    rc += xpath(int_state, "/IMAGE/STATE", 0);
    rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1);

    type  = static_cast<ImageType>(int_type);
    state = static_cast<ImageState>(int_state);

    // Get associated classes
    ObjectXML::get_nodes("/IMAGE/TEMPLATE", content);
    if( content.size() < 1 )
    {
        return -1;
    }

    rc += obj_template->from_xml_node(content[0]);

    if (rc != 0)
    {
        return -1;
    }

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::disk_attribute(  VectorAttribute * disk,
                            int *             index,
                            ImageType*        img_type)
{
    string  bus;
    string  target;
    string  driver;

    ostringstream  iid;

    *img_type = type;
    bus       = disk->vector_value("BUS");
    target    = disk->vector_value("TARGET");
    driver    = disk->vector_value("DRIVER");
    iid << oid;

    string template_bus;
    string template_target;
    string prefix;
    string template_driver;

    get_template_attribute("BUS", template_bus);
    get_template_attribute("TARGET", template_target);
    get_template_attribute("DRIVER", template_driver);

    get_template_attribute("DEV_PREFIX", prefix);

   //---------------------------------------------------------------------------
   //                       NEW DISK ATTRIBUTES
   //---------------------------------------------------------------------------

    map<string,string> new_disk;

    new_disk.insert(make_pair("IMAGE",    name));
    new_disk.insert(make_pair("IMAGE_ID", iid.str()));
    new_disk.insert(make_pair("SOURCE",   source));

    if (!bus.empty())
    {
        new_disk.insert(make_pair("BUS",bus));
    }
    else if (!template_bus.empty())
    {
        new_disk.insert(make_pair("BUS",template_bus));
    }

    if (!driver.empty())
    {
        new_disk.insert(make_pair("DRIVER",driver));
    }
    else if (!template_driver.empty())
    {
        new_disk.insert(make_pair("DRIVER",template_driver));
    }

   //---------------------------------------------------------------------------
   //   TYPE, READONLY, CLONE, and SAVE attributes
   //---------------------------------------------------------------------------

    if ( persistent_img )
    {
        new_disk.insert(make_pair("CLONE","NO"));
        new_disk.insert(make_pair("SAVE","YES"));
    }
    else
    {
        new_disk.insert(make_pair("CLONE","YES"));
        new_disk.insert(make_pair("SAVE","NO"));
    }

    switch(type)
    {
        case OS:
        case DATABLOCK:
          new_disk.insert(make_pair("TYPE","DISK"));
          new_disk.insert(make_pair("READONLY","NO"));
        break;

        case CDROM:
          new_disk.insert(make_pair("TYPE","CDROM"));
          new_disk.insert(make_pair("READONLY","YES"));
        break;
    }

   //---------------------------------------------------------------------------
   //   TARGET attribute
   //---------------------------------------------------------------------------

    if (!target.empty())
    {
        new_disk.insert(make_pair("TARGET", target));
    }
    else if (!template_target.empty())
    {
        new_disk.insert(make_pair("TARGET", template_target));
    }
    else
    {
        switch(type)
        {
            case OS:
                prefix += "a";
            break;

            case CDROM:
                prefix += "c"; // b is for context
            break;

            case DATABLOCK:
                prefix += static_cast<char>(('e'+ *index));
                *index  = *index + 1;
            break;

        }

        new_disk.insert(make_pair("TARGET", prefix));
    }

    disk->replace(new_disk);

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

string Image::sha1_digest(const string& pass)
{
    EVP_MD_CTX     mdctx;
    unsigned char  md_value[EVP_MAX_MD_SIZE];
    unsigned int   md_len;
    ostringstream  oss;

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, EVP_sha1(), NULL);

    EVP_DigestUpdate(&mdctx, pass.c_str(), pass.length());

    EVP_DigestFinal_ex(&mdctx,md_value,&md_len);
    EVP_MD_CTX_cleanup(&mdctx);

    for(unsigned int i = 0; i<md_len; i++)
    {
        oss << setfill('0') << setw(2) << hex << nouppercase
            << (unsigned short) md_value[i];
    }

    return oss.str();
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
<commit_msg>feature #559: Preserve DISK attributes when using the image repository<commit_after>/* ------------------------------------------------------------------------ */
/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)           */
/*                                                                          */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may  */
/* not use this file except in compliance with the License. You may obtain  */
/* a copy of the License at                                                 */
/*                                                                          */
/* http://www.apache.org/licenses/LICENSE-2.0                               */
/*                                                                          */
/* Unless required by applicable law or agreed to in writing, software      */
/* distributed under the License is distributed on an "AS IS" BASIS,        */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and      */
/* limitations under the License.                                           */
/* ------------------------------------------------------------------------ */

#include <limits.h>
#include <string.h>

#include <iostream>
#include <sstream>
#include <openssl/evp.h>
#include <iomanip>

#include "Image.h"
#include "ImagePool.h"

#include "AuthManager.h"
#include "UserPool.h"

#define TO_UPPER(S) transform(S.begin(),S.end(),S.begin(),(int(*)(int))toupper)

/* ************************************************************************ */
/* Image :: Constructor/Destructor                                          */
/* ************************************************************************ */

Image::Image(int             _uid,
             const string&   _user_name,
             ImageTemplate * _image_template):
        PoolObjectSQL(-1,"",_uid,table),
        user_name(_user_name),
        type(OS),
        regtime(time(0)),
        source(""),
        state(INIT),
        running_vms(0)
{
    if (_image_template != 0)
    {
        obj_template = _image_template;
    }
    else
    {
        obj_template = new ImageTemplate;
    }
}

Image::~Image()
{
    if (obj_template != 0)
    {
        delete obj_template;
    }
}

/* ************************************************************************ */
/* Image :: Database Access Functions                                       */
/* ************************************************************************ */

const char * Image::table = "image_pool";

const char * Image::db_names = "oid, name, body, uid, public";

const char * Image::db_bootstrap = "CREATE TABLE IF NOT EXISTS image_pool ("
    "oid INTEGER PRIMARY KEY, name VARCHAR(256), body TEXT, uid INTEGER, "
    "public INTEGER, UNIQUE(name,uid) )";

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

string Image::generate_source(int uid, const string& name)
{
    ostringstream tmp_hashstream;
    ostringstream tmp_sourcestream;

    tmp_hashstream << uid << ":" << name;

    tmp_sourcestream << ImagePool::source_prefix() << "/";
    tmp_sourcestream << sha1_digest(tmp_hashstream.str());

    return tmp_sourcestream.str();
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::insert(SqlDB *db, string& error_str)
{
    int rc;

    string path_attr;
    string type_att;
    string public_attr;
    string persistent_attr;
    string dev_prefix;

    // ---------------------------------------------------------------------
    // Check default image attributes
    // ---------------------------------------------------------------------

    // ------------ NAME --------------------

    get_template_attribute("NAME", name);

    // ------------ TYPE --------------------

    get_template_attribute("TYPE", type_att);

    TO_UPPER(type_att);

    if ( type_att.empty() == true )
    {
        type_att = ImagePool::default_type();
    }

    if (set_type(type_att) != 0)
    {
        goto error_type;
    }

    // ------------ PUBLIC --------------------

    get_template_attribute("PUBLIC", public_attr);

    obj_template->erase("PUBLIC");

    TO_UPPER(public_attr);

    public_img = (public_attr == "YES");

    // ------------ PERSISTENT --------------------

    get_template_attribute("PERSISTENT", persistent_attr);

    obj_template->erase("PERSISTENT");

    TO_UPPER(persistent_attr);

    persistent_img = (persistent_attr == "YES");

    // An image cannot be public and persistent simultaneously

    if ( public_img && persistent_img )
    {
        goto error_public_and_persistent;
    }

    // ------------ PREFIX --------------------

    get_template_attribute("DEV_PREFIX", dev_prefix);

    if( dev_prefix.empty() )
    {
        SingleAttribute * dev_att = new SingleAttribute("DEV_PREFIX",
                                          ImagePool::default_dev_prefix());
        obj_template->set(dev_att);
    }

    // ------------ PATH & SOURCE --------------------

    get_template_attribute("PATH", path_attr);
    get_template_attribute("SOURCE", source);

    // The template should contain PATH or SOURCE
    if ( source.empty() && path_attr.empty() )
    {
        string size_attr;
        string fstype_attr;

        istringstream iss;
        int size_mb;

        get_template_attribute("SIZE",   size_attr);
        get_template_attribute("FSTYPE", fstype_attr);

        // DATABLOCK image needs SIZE and FSTYPE
        if (type != DATABLOCK || size_attr.empty() || fstype_attr.empty())
        {
            goto error_no_path;
        }

        iss.str(size_attr);

        iss >> size_mb;

        if (iss.fail() == true)
        {
            goto error_size_format;
        }
    }
    else if ( !source.empty() && !path_attr.empty() )
    {
        goto error_path_and_source;
    }

    if (source.empty())
    {
        source = Image::generate_source(uid,name);
    }

    state = LOCKED; //LOCKED till the ImageManager copies it to the Repository

    //--------------------------------------------------------------------------
    // Insert the Image
    //--------------------------------------------------------------------------

    rc = insert_replace(db, false);

    if ( rc == -1 )
    {
        error_str = "Error inserting Image in DB.";
    }

    return rc;

error_type:
    error_str = "Incorrect TYPE in template.";
    goto error_common;

error_public_and_persistent:
    error_str = "Image cannot be public and persistent.";
    goto error_common;

error_no_path:
    if ( type == DATABLOCK )
    {
        error_str = "A DATABLOCK type IMAGE has to declare a PATH, or both "
                    "SIZE and FSTYPE.";
    }
    else
    {
        error_str = "No PATH in template.";
    }
    goto error_common;

error_size_format:
    error_str = "Wrong number in SIZE.";
    goto error_common;

error_path_and_source:
    error_str = "Template malformed, PATH and SOURCE are mutuallly exclusive.";
    goto error_common;

error_common:
    NebulaLog::log("IMG", Log::ERROR, error_str);
    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::update(SqlDB *db)
{
    return insert_replace(db, true);;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::insert_replace(SqlDB *db, bool replace)
{
    ostringstream   oss;

    int    rc;

    string xml_body;

    char * sql_name;
    char * sql_xml;

    // Update the Image

    sql_name = db->escape_str(name.c_str());

    if ( sql_name == 0 )
    {
        goto error_name;
    }

    sql_xml = db->escape_str(to_xml(xml_body).c_str());

    if ( sql_xml == 0 )
    {
        goto error_body;
    }

    if(replace)
    {
        oss << "REPLACE";
    }
    else
    {
        oss << "INSERT";
    }

    // Construct the SQL statement to Insert or Replace

    oss <<" INTO "<< table <<" ("<< db_names <<") VALUES ("
        <<          oid             << ","
        << "'" <<   sql_name        << "',"
        << "'" <<   sql_xml         << "',"
        <<          uid             << ","
        <<          public_img      << ")";

    rc = db->exec(oss);

    db->free_str(sql_name);
    db->free_str(sql_xml);

    return rc;

error_body:
    db->free_str(sql_name);
error_name:
    return -1;
}

/* ************************************************************************ */
/* Image :: Misc                                                             */
/* ************************************************************************ */

ostream& operator<<(ostream& os, Image& image)
{
    string image_str;

    os << image.to_xml(image_str);

    return os;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

string& Image::to_xml(string& xml) const
{
    string template_xml;
    ostringstream   oss;

    oss <<
        "<IMAGE>" <<
            "<ID>"             << oid             << "</ID>"          <<
            "<UID>"            << uid             << "</UID>"         <<
            "<USERNAME>"       << user_name       << "</USERNAME>"    <<
            "<NAME>"           << name            << "</NAME>"        <<
            "<TYPE>"           << type            << "</TYPE>"        <<
            "<PUBLIC>"         << public_img      << "</PUBLIC>"      <<
            "<PERSISTENT>"     << persistent_img  << "</PERSISTENT>"  <<
            "<REGTIME>"        << regtime         << "</REGTIME>"     <<
            "<SOURCE>"         << source          << "</SOURCE>"      <<
            "<STATE>"          << state           << "</STATE>"       <<
            "<RUNNING_VMS>"    << running_vms     << "</RUNNING_VMS>" <<
            obj_template->to_xml(template_xml)                      <<
        "</IMAGE>";

    xml = oss.str();

    return xml;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::from_xml(const string& xml)
{
    vector<xmlNodePtr> content;
    int int_state;
    int int_type;

    int rc = 0;

    // Initialize the internal XML object
    update_from_str(xml);

    // Get class base attributes
    rc += xpath(oid, "/IMAGE/ID", -1);
    rc += xpath(uid, "/IMAGE/UID", -1);
    rc += xpath(user_name, "/IMAGE/USERNAME", "not_found");
    rc += xpath(name, "/IMAGE/NAME", "not_found");

    rc += xpath(int_type, "/IMAGE/TYPE", 0);
    rc += xpath(public_img, "/IMAGE/PUBLIC", 0);
    rc += xpath(persistent_img, "/IMAGE/PERSISTENT", 0);
    rc += xpath(regtime, "/IMAGE/REGTIME", 0);

    rc += xpath(source, "/IMAGE/SOURCE", "not_found");
    rc += xpath(int_state, "/IMAGE/STATE", 0);
    rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1);

    type  = static_cast<ImageType>(int_type);
    state = static_cast<ImageState>(int_state);

    // Get associated classes
    ObjectXML::get_nodes("/IMAGE/TEMPLATE", content);
    if( content.size() < 1 )
    {
        return -1;
    }

    rc += obj_template->from_xml_node(content[0]);

    if (rc != 0)
    {
        return -1;
    }

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Image::disk_attribute(  VectorAttribute * disk,
                            int *             index,
                            ImageType*        img_type)
{
    string  bus;
    string  target;
    string  driver;

    ostringstream  iid;

    *img_type = type;
    bus       = disk->vector_value("BUS");
    target    = disk->vector_value("TARGET");
    driver    = disk->vector_value("DRIVER");
    iid << oid;

    string template_bus;
    string template_target;
    string prefix;
    string template_driver;

    get_template_attribute("BUS", template_bus);
    get_template_attribute("TARGET", template_target);
    get_template_attribute("DRIVER", template_driver);

    get_template_attribute("DEV_PREFIX", prefix);

   //---------------------------------------------------------------------------
   //                       BASE DISK ATTRIBUTES
   //---------------------------------------------------------------------------

    disk->replace("IMAGE",    name);
    disk->replace("IMAGE_ID", iid.str());
    disk->replace("SOURCE",   source);

    if (bus.empty() && !template_bus.empty()) //BUS in Image, not in DISK
    {
        disk->replace("BUS",template_bus);
    }

    if (driver.empty() && !template_driver.empty())//DRIVER in Image,not in DISK
    {
        disk->replace("DRIVER",template_driver);
    }

   //---------------------------------------------------------------------------
   //   TYPE, READONLY, CLONE, and SAVE attributes
   //---------------------------------------------------------------------------

    if ( persistent_img )
    {
        disk->replace("CLONE","NO");
        disk->replace("SAVE","YES");
    }
    else
    {
        disk->replace("CLONE","YES");
        disk->replace("SAVE","NO");
    }

    switch(type)
    {
        case OS:
        case DATABLOCK:
          disk->replace("TYPE","DISK");
          disk->replace("READONLY","NO");
        break;

        case CDROM:
          disk->replace("TYPE","CDROM");
          disk->replace("READONLY","YES");
        break;
    }

   //---------------------------------------------------------------------------
   //   TARGET attribute
   //---------------------------------------------------------------------------

    if (target.empty()) //No TARGET in DISK attribute
    {
        if (!template_target.empty())
        {
            disk->replace("TARGET", template_target);
        }
        else
        {
            switch(type)
            {
                case OS:
                    prefix += "a";
                break;

                case CDROM:
                    prefix += "c"; // b is for context
                break;

                case DATABLOCK:
                    prefix += static_cast<char>(('e'+ *index));
                    *index  = *index + 1;
                break;

            }

            disk->replace("TARGET", prefix);
        }
    }

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

string Image::sha1_digest(const string& pass)
{
    EVP_MD_CTX     mdctx;
    unsigned char  md_value[EVP_MAX_MD_SIZE];
    unsigned int   md_len;
    ostringstream  oss;

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, EVP_sha1(), NULL);

    EVP_DigestUpdate(&mdctx, pass.c_str(), pass.length());

    EVP_DigestFinal_ex(&mdctx,md_value,&md_len);
    EVP_MD_CTX_cleanup(&mdctx);

    for(unsigned int i = 0; i<md_len; i++)
    {
        oss << setfill('0') << setw(2) << hex << nouppercase
            << (unsigned short) md_value[i];
    }

    return oss.str();
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
<|endoftext|>