<commit_before>#include "data/data_set.h"
#include "utils/query.h"
#include "core/armor_up.h"
#include "aux/timer.h"

using namespace monster_avengers;

int main(int argc, char **argv) {
  std::setlocale(LC_ALL, "en_US.UTF-8");
  Query query;
  // Query that returns 6 skills
  CHECK_SUCCESS(Query::Parse(L"(:weapon-type \"melee\")"
                             L"(:weapon-holes 2)"
                             L"(:skill 36 10)"
                             L"(:skill 41 10)"
                             L"(:skill 40 15)"
                             // L"(:skill 30 10)",
                             &query));

  query.DebugPrint();
  Timer timer;
  timer.Tic();
  ArmorUp armor_up("/home/breakds/pf/projects/monster-avengers/dataset/MH4GU");
  double init_duration = timer.Toc();
  timer.Tic();
  armor_up.Explore(query);
  double duration = timer.Toc();
  armor_up.Summarize();
  wprintf(L"Initialization: %.4lf seconds.\n", init_duration);
  wprintf(L"Computation: %.4lf seconds.\n", duration);

  return 0;
}
<commit_msg>build fixed<commit_after>#include "data/data_set.h"
#include "utils/query.h"
#include "core/armor_up.h"
#include "aux/timer.h"

using namespace monster_avengers;

int main(int argc, char **argv) {
  std::setlocale(LC_ALL, "en_US.UTF-8");
  Query query;
  // Query that returns 6 skills
  CHECK_SUCCESS(Query::Parse(L"(:weapon-type \"melee\")"
                             L"(:weapon-holes 2)"
                             L"(:skill 36 10)"
                             L"(:skill 41 10)"
                             L"(:skill 40 15)",
                             // L"(:skill 30 10)",
                             &query));

  query.DebugPrint();
  Timer timer;
  timer.Tic();
  ArmorUp armor_up("/home/breakds/pf/projects/monster-avengers/dataset/MH4GU");
  double init_duration = timer.Toc();
  timer.Tic();
  armor_up.Explore(query);
  double duration = timer.Toc();
  armor_up.Summarize();
  wprintf(L"Initialization: %.4lf seconds.\n", init_duration);
  wprintf(L"Computation: %.4lf seconds.\n", duration);

  return 0;
}
<|endoftext|>


<commit_before>/** \file    CookieJar.cc
 *  \brief   Implementation of class CookieJar.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
 *  \copyright 2007 Project iVia.
 *  \copyright 2007 The Regents of The University of California.
 *  \copyright 2017,2019 Universitätsbibliothek Tübingen.
 *
 *  This file is part of the libiViaCore package.
 *
 *  The libiViaCore package 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 of the License, or
 *  (at your option) any later version.
 *
 *  libiViaCore 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 libiViaCore; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "CookieJar.h"
#include <algorithm>
#include <stdexcept>
#include "Compiler.h"
#include "DnsUtil.h"
#include "HttpHeader.h"
#include "StringUtil.h"
#include "TextUtil.h"
#include "WebUtil.h"

std::string CookieJar::Cookie::getCookieHeader() const {
    std::string header("Cookie: ");
    header += name_;
    if (not value_.empty())
        header += "=" + value_;
    if (not version_.empty())
        header += "; $Version=" + version_;
    if (not path_.empty())
        header += "; $Path=" + path_;
    if (not domain_.empty())
        header += "; $Domain=" + domain_;
    if (not cookies_supported_.empty())
        header += "CookiesSupported=" + cookies_supported_ + "\r\n";
    header += "\r\n";

    return header;
}

std::string CookieJar::Cookie::toString() const {
    std::string cookie_as_string;
    if (name_.empty())
        cookie_as_string = "*Empty cookie!*\n";
    else {
        cookie_as_string = name_ + "=" + value_ + "\n";
        if (not comment_.empty())
            cookie_as_string += "\tComment: " + comment_ + "\n";
        if (not comment_url_.empty())
            cookie_as_string += "\tCommentURL: " + comment_url_ + "\n";
        if (not version_.empty())
            cookie_as_string += "\tVersion: " + version_ + "\n";
        if (not domain_.empty())
            cookie_as_string += "\tDomain: " + domain_ + "\n";
        if (not port_.empty())
            cookie_as_string += "\tPort: " + port_ + "\n";
        if (not path_.empty())
            cookie_as_string += "\tPath: " + path_ + "\n";
        if (not cookies_supported_.empty())
            cookie_as_string += "\tCookiesSupported: " + cookies_supported_ + "\n";
        if (secure_)
            cookie_as_string += "\tSecure\n";
        if (discard_)
            cookie_as_string += "\tDiscard\n";
        if (http_only_)
            cookie_as_string += "\tHttpOnly\n";
        cookie_as_string += "\tExpires: " + TimeUtil::TimeTToString(expiration_time_, "%A, %d %b %Y %T GMT", TimeUtil::UTC) + "\n";
    }

    return cookie_as_string;
}

namespace {

inline bool DomainContainsNoEmbeddedDots(const std::string &domain) {
    return std::strchr(domain.c_str() + 1, '.') == nullptr;
}

inline bool RequestHostHasMoreDotsThanDomain(const std::string &domain, const std::string &request_host) {
    std::string request_host_part(StringUtil::ReplaceString(domain, "", request_host, /*global=*/false));
    return std::strchr(request_host_part.c_str(), '.') != nullptr;
}

} // unnamed namespace

bool CookieJar::Cookie::setDomain(const std::string &domain, const std::string &request_host) {
    if (domain.empty())
        return true;

    if ((domain[0] != '.') or DomainContainsNoEmbeddedDots(domain)
        or RequestHostHasMoreDotsThanDomain(domain, request_host))
        return false;

    domain_ = domain;
    return true;
}

namespace {

class MatchCookieAttributeName: public std::unary_function<std::string, bool> {
    std::string attribute_name_;
public:
    explicit MatchCookieAttributeName(const std::string &attribute_name): attribute_name_(attribute_name) { }
    bool operator()(const std::string &attribute_name_and_value) const;
};

inline bool DomainMatch(const std::string &domain_pattern, const std::string &domain_name) {
    return StringUtil::IsSuffixOf(domain_pattern, "." + domain_name);
}

} // unnamed namespace

void CookieJar::addCookies(const HttpHeader &http_header, const std::string &default_domain) {
    if (unlikely(not DnsUtil::IsValidHostName(default_domain)))
        throw std::runtime_error("in CookieJar::addCookies: default domain \"" + default_domain
                                 + "\" must be a valid hostname!");

    const std::string lowercase_default_domain(TextUtil::UTF8ToLower(default_domain));

    const std::vector<std::string> raw_cookies(http_header.getCookies());
    for (const auto &raw_cookie : raw_cookies)
        parseCookie(raw_cookie, lowercase_default_domain);
}

namespace {

bool PathMatch(const std::string &path_pattern, const std::string &path) {
    return StringUtil::IsPrefixOf(path_pattern, path);
}

} // unnamed namespace

void CookieJar::getCookieHeaders(const std::string &domain_name, const std::string &path,
                                 std::string * const cookie_headers) const
{
    cookie_headers->clear();
    const std::string lowercase_domain_name(TextUtil::UTF8ToLower(domain_name));
    const std::string normalised_path(path.empty() ? "/" : path);

    const time_t now(std::time(nullptr));
    std::vector<Cookie> matching_cookies;
    for (iterator key_and_cookie(cookies_.begin()); key_and_cookie != cookies_.end(); /* Empty */) {
        // Delete the cookie if it has expired:
        if (now > key_and_cookie->second.expiration_time_)
            cookies_.erase(key_and_cookie++);
        else {
            const Cookie cookie(key_and_cookie->second);
            const std::string domain((cookie.domain_.empty()) ? cookie.request_host_ : cookie.domain_);
            if (DomainMatch(domain, lowercase_domain_name) and (PathMatch(cookie.path_, normalised_path)))
                matching_cookies.push_back(cookie);

            ++key_and_cookie;
        }
    }

    std::sort(matching_cookies.begin(), matching_cookies.end(), PathCompare);

    // Now generate the "Cookie:" headers:
    for (std::vector<Cookie>::const_iterator matching_cookie(matching_cookies.begin());
         matching_cookie != matching_cookies.end(); ++matching_cookie)
        *cookie_headers += matching_cookie->getCookieHeader();
}

namespace {

bool ExtractAttribAndValue(std::string::const_iterator &ch, const std::string::const_iterator &end,
                           std::string * attrib_name, std::string * attrib_value)
{
    attrib_name->clear();
    attrib_value->clear();

    // Skip over leading linear space:
    while (ch != end and (*ch == ' ' or *ch == '\t'))
        ++ch;
    if (ch == end)
        return false;

    // Extract the attribute name:
    while (ch != end and *ch != '=')
        *attrib_name += *ch++;
    StringUtil::RightTrim(" \t", attrib_name);
    if (attrib_name->empty())
        return false;

    // Skip the equal sign:
    if (ch != end)
        ++ch;

    // Skip over linear space following the '=' sign:
    while (ch != end and (*ch == ' ' or *ch == '\t'))
        ++ch;

    // Do we have an attribute name without an attribute value?
    if (ch == end or *ch == ';')
        return true;

    const bool quoted_value(*ch == '"');
    if (quoted_value) {
        ++ch;
        while (ch != end and *ch != '"')
            *attrib_value += *ch++;
        if (unlikely(ch == end))
            return false;
        ++ch; // Skip over the terminating quote.

        // Skip over linear space following the '=' sign:
        while (ch != end and (*ch == ' ' or *ch == '\t'))
            ++ch;

        // Garbled input?
        if (unlikely(ch != end and *ch != ';'))
            return false;
    } else {
        while (ch != end and *ch != ';')
            *attrib_value += *ch++;
        StringUtil::RightTrim(" \t", attrib_value);
    }

    return true;
}

enum AttribType { COOKIE_NAME, KNOWN_ATTRIB, DOMAIN_ATTRIB, RESERVED_ATTRIB };
AttribType GetAttribType(const std::string &attrib_name) {
    if (unlikely(attrib_name.empty()))
        throw std::runtime_error("in GetAttribType (CookieJar.cc): can't determine the type of name of an empty string!");

    if (attrib_name[0] == '$')
        return RESERVED_ATTRIB;

    const std::string lowercase_attrib_name(StringUtil::ASCIIToLower(attrib_name));
    if (lowercase_attrib_name == "comment")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "domain")
        return DOMAIN_ATTRIB;
    if (lowercase_attrib_name == "max-age")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "path")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "secure")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "version")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "expires")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "port")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "discard")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "commenturl")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "httponly")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "cookiessupported")
        return KNOWN_ATTRIB;

    return COOKIE_NAME;
}

// PortListIsValid -- checks to see that the ports are linear whitespace separated.
//
bool PortListIsValid(const std::string &port_list_candidate) {
    std::vector<std::string> port_candidates;
    StringUtil::SplitThenTrimWhite(port_list_candidate, " \t", &port_candidates);

    for (const auto &port_candidate : port_candidates) {
        if (unlikely(not StringUtil::IsUnsignedNumber(port_candidate)))
            return false;
    }

    return true;
}

bool UpdateKnownAttrib(const std::string &attrib_name, const std::string &attrib_value, CookieJar::Cookie * const cookie) {
    const std::string lowercase_attrib_name(StringUtil::ASCIIToLower(attrib_name));
    if (lowercase_attrib_name == "comment") {
        if (unlikely(attrib_value.empty()))
            return false;

        cookie->comment_ = attrib_value;
        return true;
    }

    if (lowercase_attrib_name == "max-age") {
        unsigned seconds_from_now;
        if (unlikely(not StringUtil::ToUnsigned(attrib_value, &seconds_from_now) or seconds_from_now == 0))
            return false;

        cookie->expiration_time_ = std::time(nullptr) + seconds_from_now;
        return true;
    }

    if (lowercase_attrib_name == "path") {
        cookie->path_ = attrib_value;
        return true;
    }

    if (lowercase_attrib_name == "secure") {
        if (unlikely(not attrib_value.empty()))
            return false;

        cookie->secure_ = true;
        return true;
    }

    if (lowercase_attrib_name == "version") {
        cookie->version_ = attrib_value; // We intentionally don't check for compliance with the spec.
        return true;
    }

    if (lowercase_attrib_name == "expires") {
        if (unlikely(attrib_value.empty()))
            return false;

        cookie->expiration_time_ = WebUtil::ParseWebDateAndTime(attrib_value);
        return cookie->expiration_time_ != TimeUtil::BAD_TIME_T;
    }

    if (lowercase_attrib_name == "port") {
        if (unlikely(not PortListIsValid(attrib_value)))
            return false;

        cookie->port_ = attrib_value;
        return true;
    }

    if (lowercase_attrib_name == "discard") {
        if (unlikely(not attrib_value.empty()))
            return false;

        cookie->discard_ = true;
        return true;
    }

    if (lowercase_attrib_name == "httponly") {
        if (unlikely(not attrib_value.empty()))
            return false;

        cookie->http_only_ = true;
        return true;
    }

    if (lowercase_attrib_name == "commenturl") {
        if (unlikely(attrib_value.empty()))
            return false;

        cookie->comment_url_ = attrib_value;
        return true;
    }

    if (lowercase_attrib_name == "cookiessupported") {
        if (unlikely(attrib_value.empty()))
            return false;

        cookie->cookies_supported_ = attrib_value;
        return true;
    }

    throw std::runtime_error("in UpdateKnownAttrib (CookieJar.cc): unknown \"known\" attribute name \"" + attrib_name
                             + "\"!");
}

} // unnamed namespace

void CookieJar::parseCookie(const std::string &raw_cookie, const std::string &default_domain) {
    Cookie cookie;
    std::string name, value;
    std::string::const_iterator ch(raw_cookie.begin());
    while (ch != raw_cookie.end()) {
        if (not ExtractAttribAndValue(ch, raw_cookie.end(), &name, &value))
            break;

        switch (GetAttribType(name)) {
        case COOKIE_NAME:
            // Take care of the previous cookie if there was one:
            if (not cookie.empty()) {
                cookie.request_host_ = default_domain;
                addCookie(cookie);
            }
            cookie = Cookie(name, value);
            break;
        case KNOWN_ATTRIB: {
            // Must follow a cookie name:
            if (unlikely(cookie.empty()))
                return; // Garbage!

            if (not UpdateKnownAttrib(name, value, &cookie))
                return; // Garbage!
            break;
        }
        case DOMAIN_ATTRIB:
            if (not cookie.setDomain(value, default_domain))
                return; // Violated RFC2109 4.3.2
            break;
        case RESERVED_ATTRIB:
            /* Ignore! */
            break;
        default:
            throw std::runtime_error("in CookieJar::parseCookie: unknown attribute type!");
        }

        // If we have more data we need to skip over a semicolon:
        if (ch != raw_cookie.end()) {
            if (unlikely(*ch != ';'))
                throw std::runtime_error("in CookieJar::parseCookie: this condition should *never* happen! "
                                         "(Remainder of text is \""
                                         + StringUtil::CStyleEscape(std::string(ch, raw_cookie.end())) + "\".)\n"
                                         "(Full cookie text is \"" + raw_cookie + "\".)");
            ++ch;
        }
    }

    if (not cookie.empty()) {
        cookie.request_host_ = default_domain;
        addCookie(cookie);
    }
}
<commit_msg>Update CookieJar.cc<commit_after>/** \file    CookieJar.cc
 *  \brief   Implementation of class CookieJar.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
 *  \copyright 2007 Project iVia.
 *  \copyright 2007 The Regents of The University of California.
 *  \copyright 2017,2019 Universitätsbibliothek Tübingen.
 *
 *  This file is part of the libiViaCore package.
 *
 *  The libiViaCore package 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 of the License, or
 *  (at your option) any later version.
 *
 *  libiViaCore 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 libiViaCore; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "CookieJar.h"
#include <algorithm>
#include <stdexcept>
#include "Compiler.h"
#include "DnsUtil.h"
#include "HttpHeader.h"
#include "StringUtil.h"
#include "TextUtil.h"
#include "WebUtil.h"

std::string CookieJar::Cookie::getCookieHeader() const {
    std::string header("Cookie: ");
    header += name_;
    if (not value_.empty())
        header += "=" + value_;
    if (not version_.empty())
        header += "; $Version=" + version_;
    if (not path_.empty())
        header += "; $Path=" + path_;
    if (not domain_.empty())
        header += "; $Domain=" + domain_;
    if (not cookies_supported_.empty())
        header += "CookiesSupported=" + cookies_supported_ + "\r\n";
    header += "\r\n";

    return header;
}

std::string CookieJar::Cookie::toString() const {
    std::string cookie_as_string;
    if (name_.empty())
        cookie_as_string = "*Empty cookie!*\n";
    else {
        cookie_as_string = name_ + "=" + value_ + "\n";
        if (not comment_.empty())
            cookie_as_string += "\tComment: " + comment_ + "\n";
        if (not comment_url_.empty())
            cookie_as_string += "\tCommentURL: " + comment_url_ + "\n";
        if (not version_.empty())
            cookie_as_string += "\tVersion: " + version_ + "\n";
        if (not domain_.empty())
            cookie_as_string += "\tDomain: " + domain_ + "\n";
        if (not port_.empty())
            cookie_as_string += "\tPort: " + port_ + "\n";
        if (not path_.empty())
            cookie_as_string += "\tPath: " + path_ + "\n";
        if (not cookies_supported_.empty())
            cookie_as_string += "\tCookiesSupported: " + cookies_supported_ + "\n";
        if (secure_)
            cookie_as_string += "\tSecure\n";
        if (discard_)
            cookie_as_string += "\tDiscard\n";
        if (http_only_)
            cookie_as_string += "\tHttpOnly\n";
        cookie_as_string += "\tExpires: " + TimeUtil::TimeTToString(expiration_time_, "%a, %d %b %Y %T GMT", TimeUtil::UTC) + "\n";
    }

    return cookie_as_string;
}

namespace {

inline bool DomainContainsNoEmbeddedDots(const std::string &domain) {
    return std::strchr(domain.c_str() + 1, '.') == nullptr;
}

inline bool RequestHostHasMoreDotsThanDomain(const std::string &domain, const std::string &request_host) {
    std::string request_host_part(StringUtil::ReplaceString(domain, "", request_host, /*global=*/false));
    return std::strchr(request_host_part.c_str(), '.') != nullptr;
}

} // unnamed namespace

bool CookieJar::Cookie::setDomain(const std::string &domain, const std::string &request_host) {
    if (domain.empty())
        return true;

    if ((domain[0] != '.') or DomainContainsNoEmbeddedDots(domain)
        or RequestHostHasMoreDotsThanDomain(domain, request_host))
        return false;

    domain_ = domain;
    return true;
}

namespace {

class MatchCookieAttributeName: public std::unary_function<std::string, bool> {
    std::string attribute_name_;
public:
    explicit MatchCookieAttributeName(const std::string &attribute_name): attribute_name_(attribute_name) { }
    bool operator()(const std::string &attribute_name_and_value) const;
};

inline bool DomainMatch(const std::string &domain_pattern, const std::string &domain_name) {
    return StringUtil::IsSuffixOf(domain_pattern, "." + domain_name);
}

} // unnamed namespace

void CookieJar::addCookies(const HttpHeader &http_header, const std::string &default_domain) {
    if (unlikely(not DnsUtil::IsValidHostName(default_domain)))
        throw std::runtime_error("in CookieJar::addCookies: default domain \"" + default_domain
                                 + "\" must be a valid hostname!");

    const std::string lowercase_default_domain(TextUtil::UTF8ToLower(default_domain));

    const std::vector<std::string> raw_cookies(http_header.getCookies());
    for (const auto &raw_cookie : raw_cookies)
        parseCookie(raw_cookie, lowercase_default_domain);
}

namespace {

bool PathMatch(const std::string &path_pattern, const std::string &path) {
    return StringUtil::IsPrefixOf(path_pattern, path);
}

} // unnamed namespace

void CookieJar::getCookieHeaders(const std::string &domain_name, const std::string &path,
                                 std::string * const cookie_headers) const
{
    cookie_headers->clear();
    const std::string lowercase_domain_name(TextUtil::UTF8ToLower(domain_name));
    const std::string normalised_path(path.empty() ? "/" : path);

    const time_t now(std::time(nullptr));
    std::vector<Cookie> matching_cookies;
    for (iterator key_and_cookie(cookies_.begin()); key_and_cookie != cookies_.end(); /* Empty */) {
        // Delete the cookie if it has expired:
        if (now > key_and_cookie->second.expiration_time_)
            cookies_.erase(key_and_cookie++);
        else {
            const Cookie cookie(key_and_cookie->second);
            const std::string domain((cookie.domain_.empty()) ? cookie.request_host_ : cookie.domain_);
            if (DomainMatch(domain, lowercase_domain_name) and (PathMatch(cookie.path_, normalised_path)))
                matching_cookies.push_back(cookie);

            ++key_and_cookie;
        }
    }

    std::sort(matching_cookies.begin(), matching_cookies.end(), PathCompare);

    // Now generate the "Cookie:" headers:
    for (std::vector<Cookie>::const_iterator matching_cookie(matching_cookies.begin());
         matching_cookie != matching_cookies.end(); ++matching_cookie)
        *cookie_headers += matching_cookie->getCookieHeader();
}

namespace {

bool ExtractAttribAndValue(std::string::const_iterator &ch, const std::string::const_iterator &end,
                           std::string * attrib_name, std::string * attrib_value)
{
    attrib_name->clear();
    attrib_value->clear();

    // Skip over leading linear space:
    while (ch != end and (*ch == ' ' or *ch == '\t'))
        ++ch;
    if (ch == end)
        return false;

    // Extract the attribute name:
    while (ch != end and *ch != '=')
        *attrib_name += *ch++;
    StringUtil::RightTrim(" \t", attrib_name);
    if (attrib_name->empty())
        return false;

    // Skip the equal sign:
    if (ch != end)
        ++ch;

    // Skip over linear space following the '=' sign:
    while (ch != end and (*ch == ' ' or *ch == '\t'))
        ++ch;

    // Do we have an attribute name without an attribute value?
    if (ch == end or *ch == ';')
        return true;

    const bool quoted_value(*ch == '"');
    if (quoted_value) {
        ++ch;
        while (ch != end and *ch != '"')
            *attrib_value += *ch++;
        if (unlikely(ch == end))
            return false;
        ++ch; // Skip over the terminating quote.

        // Skip over linear space following the '=' sign:
        while (ch != end and (*ch == ' ' or *ch == '\t'))
            ++ch;

        // Garbled input?
        if (unlikely(ch != end and *ch != ';'))
            return false;
    } else {
        while (ch != end and *ch != ';')
            *attrib_value += *ch++;
        StringUtil::RightTrim(" \t", attrib_value);
    }

    return true;
}

enum AttribType { COOKIE_NAME, KNOWN_ATTRIB, DOMAIN_ATTRIB, RESERVED_ATTRIB };
AttribType GetAttribType(const std::string &attrib_name) {
    if (unlikely(attrib_name.empty()))
        throw std::runtime_error("in GetAttribType (CookieJar.cc): can't determine the type of name of an empty string!");

    if (attrib_name[0] == '$')
        return RESERVED_ATTRIB;

    const std::string lowercase_attrib_name(StringUtil::ASCIIToLower(attrib_name));
    if (lowercase_attrib_name == "comment")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "domain")
        return DOMAIN_ATTRIB;
    if (lowercase_attrib_name == "max-age")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "path")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "secure")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "version")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "expires")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "port")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "discard")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "commenturl")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "httponly")
        return KNOWN_ATTRIB;
    if (lowercase_attrib_name == "cookiessupported")
        return KNOWN_ATTRIB;

    return COOKIE_NAME;
}

// PortListIsValid -- checks to see that the ports are linear whitespace separated.
//
bool PortListIsValid(const std::string &port_list_candidate) {
    std::vector<std::string> port_candidates;
    StringUtil::SplitThenTrimWhite(port_list_candidate, " \t", &port_candidates);

    for (const auto &port_candidate : port_candidates) {
        if (unlikely(not StringUtil::IsUnsignedNumber(port_candidate)))
            return false;
    }

    return true;
}

bool UpdateKnownAttrib(const std::string &attrib_name, const std::string &attrib_value, CookieJar::Cookie * const cookie) {
    const std::string lowercase_attrib_name(StringUtil::ASCIIToLower(attrib_name));
    if (lowercase_attrib_name == "comment") {
        if (unlikely(attrib_value.empty()))
            return false;

        cookie->comment_ = attrib_value;
        return true;
    }

    if (lowercase_attrib_name == "max-age") {
        unsigned seconds_from_now;
        if (unlikely(not StringUtil::ToUnsigned(attrib_value, &seconds_from_now) or seconds_from_now == 0))
            return false;

        cookie->expiration_time_ = std::time(nullptr) + seconds_from_now;
        return true;
    }

    if (lowercase_attrib_name == "path") {
        cookie->path_ = attrib_value;
        return true;
    }

    if (lowercase_attrib_name == "secure") {
        if (unlikely(not attrib_value.empty()))
            return false;

        cookie->secure_ = true;
        return true;
    }

    if (lowercase_attrib_name == "version") {
        cookie->version_ = attrib_value; // We intentionally don't check for compliance with the spec.
        return true;
    }

    if (lowercase_attrib_name == "expires") {
        if (unlikely(attrib_value.empty()))
            return false;

        cookie->expiration_time_ = WebUtil::ParseWebDateAndTime(attrib_value);
        return cookie->expiration_time_ != TimeUtil::BAD_TIME_T;
    }

    if (lowercase_attrib_name == "port") {
        if (unlikely(not PortListIsValid(attrib_value)))
            return false;

        cookie->port_ = attrib_value;
        return true;
    }

    if (lowercase_attrib_name == "discard") {
        if (unlikely(not attrib_value.empty()))
            return false;

        cookie->discard_ = true;
        return true;
    }

    if (lowercase_attrib_name == "httponly") {
        if (unlikely(not attrib_value.empty()))
            return false;

        cookie->http_only_ = true;
        return true;
    }

    if (lowercase_attrib_name == "commenturl") {
        if (unlikely(attrib_value.empty()))
            return false;

        cookie->comment_url_ = attrib_value;
        return true;
    }

    if (lowercase_attrib_name == "cookiessupported") {
        if (unlikely(attrib_value.empty()))
            return false;

        cookie->cookies_supported_ = attrib_value;
        return true;
    }

    throw std::runtime_error("in UpdateKnownAttrib (CookieJar.cc): unknown \"known\" attribute name \"" + attrib_name
                             + "\"!");
}

} // unnamed namespace

void CookieJar::parseCookie(const std::string &raw_cookie, const std::string &default_domain) {
    Cookie cookie;
    std::string name, value;
    std::string::const_iterator ch(raw_cookie.begin());
    while (ch != raw_cookie.end()) {
        if (not ExtractAttribAndValue(ch, raw_cookie.end(), &name, &value))
            break;

        switch (GetAttribType(name)) {
        case COOKIE_NAME:
            // Take care of the previous cookie if there was one:
            if (not cookie.empty()) {
                cookie.request_host_ = default_domain;
                addCookie(cookie);
            }
            cookie = Cookie(name, value);
            break;
        case KNOWN_ATTRIB: {
            // Must follow a cookie name:
            if (unlikely(cookie.empty()))
                return; // Garbage!

            if (not UpdateKnownAttrib(name, value, &cookie))
                return; // Garbage!
            break;
        }
        case DOMAIN_ATTRIB:
            if (not cookie.setDomain(value, default_domain))
                return; // Violated RFC2109 4.3.2
            break;
        case RESERVED_ATTRIB:
            /* Ignore! */
            break;
        default:
            throw std::runtime_error("in CookieJar::parseCookie: unknown attribute type!");
        }

        // If we have more data we need to skip over a semicolon:
        if (ch != raw_cookie.end()) {
            if (unlikely(*ch != ';'))
                throw std::runtime_error("in CookieJar::parseCookie: this condition should *never* happen! "
                                         "(Remainder of text is \""
                                         + StringUtil::CStyleEscape(std::string(ch, raw_cookie.end())) + "\".)\n"
                                         "(Full cookie text is \"" + raw_cookie + "\".)");
            ++ch;
        }
    }

    if (not cookie.empty()) {
        cookie.request_host_ = default_domain;
        addCookie(cookie);
    }
}
<|endoftext|>


<commit_before>/** \file mysql_list_tables.cc
 *  \brief A tool for listing the schemas of all tables in a MySQL database.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <memory>
#include <cstdlib>
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "StringUtil.h"
#include "util.h"

[[noreturn]] static void Usage() {
    ::Usage("[database_name user [password [host [port]]]]");
}

int Main(int argc, char *argv[]) {
    if (argc != 1 and argc != 3 and argc != 4 and argc != 5 and argc != 6)
        Usage();

    std::unique_ptr<DbConnection> db_connection;
    switch (argc) {
    case 1:
        db_connection.reset(new DbConnection());
        break;
    case 3:
        db_connection.reset(new DbConnection(argv[1], argv[2]));
        break;
    case 4:
        db_connection.reset(new DbConnection(argv[1], argv[2], argv[3]));
        break;
    case 5:
        db_connection.reset(new DbConnection(argv[1], argv[2], argv[3], argv[4]));
        break;
    case 6:
        db_connection.reset(new DbConnection(argv[1], argv[2], argv[3], argv[4], StringUtil::ToUnsigned(argv[5])));
        break;
    }

    db_connection->queryOrDie("SHOW TABLES");
    std::vector<std::string> table_names;

    DbResultSet result_set1(db_connection->getLastResultSet());
    DbRow row1;
    while (row1 = result_set1.getNextRow()) {
        db_connection->queryOrDie("SHOW CREATE TABLE ub_tools." + row1[0]);
        DbResultSet result_set2(db_connection->getLastResultSet());
        DbRow row2;
        while (row2 = result_set2.getNextRow())
            std::cout << row2[1] << '\n';
    }

    return EXIT_SUCCESS;
}
<commit_msg>Fixed a bug.<commit_after>/** \file mysql_list_tables.cc
 *  \brief A tool for listing the schemas of all tables in a MySQL database.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <memory>
#include <cstdlib>
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "StringUtil.h"
#include "util.h"

[[noreturn]] static void Usage() {
    ::Usage("[database_name user [password [host [port]]]]");
}

int Main(int argc, char *argv[]) {
    if (argc != 1 and argc != 3 and argc != 4 and argc != 5 and argc != 6)
        Usage();

    const std::string database_name(argc == 1 ? "ub_tools" : argv[1]);
    std::unique_ptr<DbConnection> db_connection;
    switch (argc) {
    case 1:
        db_connection.reset(new DbConnection());
        break;
    case 3:
        db_connection.reset(new DbConnection(database_name, argv[2]));
        break;
    case 4:
        db_connection.reset(new DbConnection(database_name, argv[2], argv[3]));
        break;
    case 5:
        db_connection.reset(new DbConnection(database_name, argv[2], argv[3], argv[4]));
        break;
    case 6:
        db_connection.reset(new DbConnection(database_name, argv[2], argv[3], argv[4], StringUtil::ToUnsigned(argv[5])));
        break;
    }

    db_connection->queryOrDie("SHOW TABLES");
    std::vector<std::string> table_names;

    DbResultSet result_set1(db_connection->getLastResultSet());
    DbRow row1;
    while (row1 = result_set1.getNextRow()) {
        db_connection->queryOrDie("SHOW CREATE TABLE " + database_name + "." + row1[0]);
        DbResultSet result_set2(db_connection->getLastResultSet());
        DbRow row2;
        while (row2 = result_set2.getNextRow())
            std::cout << row2[1] << '\n';
    }

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/** \file    new_journal_alert.cc
 *  \brief   Detects new journal issues for subscribed users.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <fstream>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <cstdlib>
#include <cstring>
#include "DbConnection.h"
#include "DirectoryEntry.h"
#include "Leader.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"
#include "VuFind.h"

void Usage() {
    std::cerr << "Usage: " << ::progname << " [-v|--verbose] marc_input notification_log_filename\n";
    std::cerr << "  Sends out notification emails for journal subscribers.\n";
    std::exit(EXIT_FAILURE);
}

inline bool AllDigits(const std::string &s) {
    for (char ch : s) {
        if (not StringUtil::IsDigit(ch))
            return false;
    }

    return true;
}

bool IsValidDate(const std::string &date_string) {
    if (unlikely(date_string.length() != 6))
        return false;

    if (unlikely(not AllDigits(date_string)))
        return false;

    const unsigned day_candidate(date_string[0] - '0' + (date_string[1] - '0') * 10);
    if (unlikely(day_candidate < 1 or day_candidate > 31))
        return false;

    const unsigned month_candidate(date_string[3] - '0' + (date_string[2] - '0') * 10);
    if (unlikely(month_candidate < 1 or month_candidate > 12))
        return false;

    return true;
}

void CreateNotificationLog(const bool verbose, File * const marc_input, File * const /*notification_log_output*/) {
    if (verbose)
        std::cout << "Starting parsing of MARC input.\n";

    unsigned count(0), serial_record_count(0), matched_serial_count(0);
    std::string err_msg;
    while (const MarcUtil::Record record = MarcUtil::Record::XmlFactory(marc_input)) {
        ++count;

	const Leader &leader(record.getLeader());
        if (not leader.isSerial())
            continue;

	const std::vector<std::string> &fields(record.getFields());

        const ssize_t _008_index(record.getFieldIndex("008"));
        if (_008_index == -1) {
            std::cerr << "008 field is missing for the record with the control number " << fields[0] << ".\n";
            continue;
        }

        // Extract the date:
        const std::string date_string(fields[_008_index].substr(0, 5));
        if (unlikely(not IsValidDate(date_string))) {
            std::cerr << "Record with the control number " << fields[0] << " has a bad date \""
                      << date_string << "\".\n";
            continue;
        }
    }

    if (not err_msg.empty())
        Error(err_msg);

    if (verbose) {
        std::cerr << "Read " << count << " records.\n";
        std::cerr << "Found " << serial_record_count << " serial recordss.\n";
        std::cerr << "Logged " << matched_serial_count << " serial records.\n";
    }
}

std::unique_ptr<File> OpenInputFile(const std::string &filename) {
    std::string mode("r");
    mode += MediaTypeUtil::GetFileMediaType(filename) == "application/lz4" ? "u" : "";
    std::unique_ptr<File> file(new File(filename, mode));
    if (file == nullptr)
        Error("can't open \"" + filename + "\" for reading!");

    return file;
}

struct JournalTitleAndLastIssueDate {
    std::string journal_title_;
    std::string last_issue_date_; // YYYYMMDD
public:
    JournalTitleAndLastIssueDate(const std::string &journal_title, const std::string &last_issue_date)
        : journal_title_(journal_title), last_issue_date_(last_issue_date) { }

    inline bool operator==(const JournalTitleAndLastIssueDate &rhs) const {
        return journal_title_ == rhs.journal_title_;
    }
};

template <> struct std::hash<JournalTitleAndLastIssueDate> {
    std::size_t operator()(const JournalTitleAndLastIssueDate &journal_title_and_last_issue_date) const {
        return std::hash<std::string>()(journal_title_and_last_issue_date.journal_title_);
    }
};

struct JournalSubscriberInfo {
    std::string email_address_;
    std::string first_name_;
    std::string last_name_;
    std::unordered_set<JournalTitleAndLastIssueDate> journal_titles_and_last_issue_dates_;
public:
    JournalSubscriberInfo(const std::string &email_address, const std::string &first_name,
                          const std::string &last_name)
        : email_address_(email_address), first_name_(first_name), last_name_(last_name) { }
    void addJournalTitleAndLastIssueDate(const JournalTitleAndLastIssueDate &new_journal_title_and_last_issue_date) {
        journal_titles_and_last_issue_dates_.insert(new_journal_title_and_last_issue_date);
    }
};

// Populates the user-specific parts of a JournalSubscriberInfo struct with data found in the vufind.user table.
JournalSubscriberInfo GetJournalSubscriberInfo(DbConnection * const db_connection, const std::string &user_id) {
    const std::string SELECT_STMT("SELECT email,firstname,lastname FROM user WHERE id=" + user_id);
    if (unlikely(not db_connection->query(SELECT_STMT)))
        Error("Select failed: " + SELECT_STMT + " (" + db_connection->getLastErrorMessage() + ")");
    DbResultSet result_set(db_connection->getLastResultSet());
    if (unlikely(result_set.empty())) // This should be impossible!
        throw std::runtime_error("result set was empty for query: " + SELECT_STMT);
    const DbRow row(result_set.getNextRow());
    return JournalSubscriberInfo(row["email"], row["firstname"], row["lastname"]);
}

void GetUsersAndJournals(
    DbConnection * const db_connection,
    std::vector<std::pair<JournalSubscriberInfo, std::unordered_set<JournalTitleAndLastIssueDate>>>
        * const users_and_journals)
{
    users_and_journals->clear();

    const std::string SELECT_IDS_STMT("SELECT DISTINCT id FROM ixtheo_journal_subscriptions");
    if (unlikely(not db_connection->query(SELECT_IDS_STMT)))
	Error("Select failed: " + SELECT_IDS_STMT + " (" + db_connection->getLastErrorMessage() + ")");

    DbResultSet id_result_set(db_connection->getLastResultSet());
    while (const DbRow id_row = id_result_set.getNextRow()) {
        const std::string user_id(id_row["id"]);
        const JournalSubscriberInfo new_journal_subscriber_info(GetJournalSubscriberInfo(db_connection, user_id));

        const std::string SELECT_TITLES_AND_DATES_STMT("SELECT journal_title,last_issue_date FROM "
                                                       "ixtheo_journal_subscriptions WHERE id=" + user_id);
        if (unlikely(not db_connection->query(SELECT_TITLES_AND_DATES_STMT)))
            Error("Select failed: " + SELECT_TITLES_AND_DATES_STMT + " (" + db_connection->getLastErrorMessage()
                  + ")");
        DbResultSet result_set(db_connection->getLastResultSet());
        std::unordered_set<JournalTitleAndLastIssueDate> titles_and_dates;
        while (const DbRow row = result_set.getNextRow())
            titles_and_dates.emplace(row["journal_title"], row["last_issue_date"]);
        users_and_journals->emplace_back(std::make_pair(new_journal_subscriber_info, titles_and_dates));
    }
}

void PopulateJournalTitleToUserInfoMap(
    const std::vector<std::pair<JournalSubscriberInfo, std::unordered_set<JournalTitleAndLastIssueDate>>>
        &users_and_journals,
    std::unordered_map<std::string, std::vector<JournalSubscriberInfo const *>> * const
        journal_title_to_user_info_map)
{
    journal_title_to_user_info_map->clear();

    for (const auto &user_and_journals : users_and_journals) {
        for (const auto &title_and_date : user_and_journals.second) {
            auto journal_title_and_user_infos(journal_title_to_user_info_map->find(title_and_date.journal_title_));
            if (journal_title_and_user_infos == journal_title_to_user_info_map->end()) {
                journal_title_to_user_info_map->emplace(title_and_date.journal_title_,
                                                        std::vector<JournalSubscriberInfo const *>());
                journal_title_and_user_infos = journal_title_to_user_info_map->find(title_and_date.journal_title_);
            }
            journal_title_and_user_infos->second.emplace_back(&user_and_journals.first);
        }
    }
}

int main(int argc, char **argv) {
    progname = argv[0];

    if ((argc != 3 and argc != 4)
        or (argc == 4 and std::strcmp(argv[1], "-v") != 0 and std::strcmp(argv[1], "--verbose") != 0))
        Usage();
    const bool verbose(argc == 3);

    const std::string marc_input_filename(argv[argc == 4 ? 2 : 1]);
    std::unique_ptr<File> marc_input(OpenInputFile(marc_input_filename));

    try {
	std::string mysql_url;
	VuFind::GetMysqlURL(&mysql_url);
	DbConnection db_connection(mysql_url);
        std::vector<std::pair<JournalSubscriberInfo, std::unordered_set<JournalTitleAndLastIssueDate>>>
            users_and_journals;
        GetUsersAndJournals(&db_connection, &users_and_journals);
        if (verbose)
            std::cout << "Found entries for " << users_and_journals.size()
                      << " users that are interested in notifications.\n";

        std::unordered_map<std::string, std::vector<JournalSubscriberInfo const *>> journal_title_to_user_info_map;
        PopulateJournalTitleToUserInfoMap(users_and_journals, &journal_title_to_user_info_map);
        if (verbose)
            std::cout << "Found " << journal_title_to_user_info_map.size()
                      << " serials for which there is at least one subscriber each.\n";

        const std::string notification_log_filename(argv[verbose ? 3 : 2]);
        File notification_log_output(notification_log_filename, "w");
        if (not notification_log_output)
            Error("can't open \"" + notification_log_filename + "\" for writing!");

        CreateNotificationLog(verbose, marc_input.get(), &notification_log_output);
    } catch (const std::exception &x) {
	Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Work in progress.<commit_after>/** \file    new_journal_alert.cc
 *  \brief   Detects new journal issues for subscribed users.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <vector>
#include <cstdlib>
#include <cstring>
#include "Compiler.h"
#include "DbConnection.h"
#include "Solr.h"
#include "StringUtil.h"
#include "UrlUtil.h"
#include "util.h"
#include "VuFind.h"

void Usage() {
    std::cerr << "Usage: " << ::progname << " [--verbose] [solr_host_and_port]\n";
    std::cerr << "  Sends out notification emails for journal subscribers.\n";
    std::cerr << "  Should \"solr_host_and_port\" be missing \"localhost:8080\" will be used.\n";
    std::exit(EXIT_FAILURE);
}

struct SerialControlNumberAndLastIssueDate {
    std::string serial_control_number_;
    std::string last_issue_date_;
public:
    SerialControlNumberAndLastIssueDate(const std::string &serial_control_number, const std::string &last_issue_date)
        : serial_control_number_(serial_control_number), last_issue_date_(last_issue_date) { }
};

struct NewIssueInfo {
};

void GetNewIssues(const std::string &solr_host_and_port, const std::string &serial_control_number,
                  const std::string &last_issue_date, std::vector<NewIssueInfo> * const /*new_issue_infos*/)
{
    const std::string QUERY("superior_ppn: " + serial_control_number + " AND last_issue_date:" + last_issue_date);
    std::string xml_result;
    if (unlikely(not Solr::Query(QUERY, "title,author", &xml_result, solr_host_and_port))) {
        std::cerr << "Solr query failed or timed-out: \"" << QUERY << "\".\n";
        return;
    }

}

void SendNotificationEmail(const std::string &/*firstname*/, const std::string &/*lastname*/, const std::string &/*email*/,
                           const std::vector<NewIssueInfo> &/*new_issue_infos*/)
{
}

void ProcessSingleUser(const bool verbose, DbConnection * const db_connection, const std::string &user_id,
                       const std::string &solr_host_and_port,
                       const std::vector<SerialControlNumberAndLastIssueDate> &control_numbers_and_last_issue_dates)
{
    const std::string SELECT_USER_ATTRIBUTES("SELECT * FROM user WHERE id=" + user_id);
    if (unlikely(not db_connection->query(SELECT_USER_ATTRIBUTES)))
	Error("Select failed: " + SELECT_USER_ATTRIBUTES + " (" + db_connection->getLastErrorMessage() + ")");
    DbResultSet result_set(db_connection->getLastResultSet());
    if (result_set.empty())
        Error("found no user atttributes in table \"user\" for ID \"" + user_id + "\"!");
    if (result_set.size() > 1)
        Error("found multiple user atttribute sets in table \"user\" for ID \"" + user_id + "\"!");

    const DbRow row(result_set.getNextRow());
    const std::string username(row["username"]);
    if (verbose)
        std::cerr << "Found " << control_numbers_and_last_issue_dates.size() << " subscriptions for \"" << username
                  << ".\n";

    const std::string firstname(row["firstname"]);
    const std::string lastname(row["lastname"]);
    const std::string email(row["email"]);

    std::vector<NewIssueInfo> new_issue_infos;
    for (const auto &control_number_and_last_issue_date : control_numbers_and_last_issue_dates)
        GetNewIssues(solr_host_and_port, control_number_and_last_issue_date.serial_control_number_,
                     control_number_and_last_issue_date.last_issue_date_, &new_issue_infos);
    if (verbose)
        std::cerr << "Found " << new_issue_infos.size() << " new issues for " << " \"" << username << "\".\n";
    if (not new_issue_infos.empty())
        SendNotificationEmail(firstname, lastname, email, new_issue_infos);
}

void ProcessSubscriptions(const bool verbose, DbConnection * const db_connection,
                          const std::string &solr_host_and_port)
{
    const std::string SELECT_STMT("SELECT * FROM ixtheo_journal_subscriptions ORDER BY id");
    if (unlikely(not db_connection->query(SELECT_STMT)))
	Error("Select failed: " + SELECT_STMT + " (" + db_connection->getLastErrorMessage() + ")");

    std::string current_id;
    std::vector<SerialControlNumberAndLastIssueDate> control_numbers_and_last_issue_dates;
    DbResultSet id_result_set(db_connection->getLastResultSet());
    unsigned user_count(0), subscription_count(0);
    while (const DbRow id_row = id_result_set.getNextRow()) {
        const std::string user_id(id_row["id"]);

        if (user_id != current_id) {
            ++user_count;
            if (not control_numbers_and_last_issue_dates.empty())
                ProcessSingleUser(verbose, db_connection, current_id, solr_host_and_port,
                                  control_numbers_and_last_issue_dates);
            current_id = user_id;
        }

        control_numbers_and_last_issue_dates.emplace_back(SerialControlNumberAndLastIssueDate(
            id_row["journal_control_number"], id_row["last_issue_date"]));
        ++subscription_count;
    }

    if (not control_numbers_and_last_issue_dates.empty())
        ProcessSingleUser(verbose, db_connection, current_id, solr_host_and_port, control_numbers_and_last_issue_dates);

    if (verbose)
        std::cout << "Processed " << user_count << " users and " << subscription_count << " subscriptions.\n";
}

int main(int argc, char **argv) {
    progname = argv[0];

    if (argc > 3)
        Usage();

    bool verbose(false);
    std::string solr_host_and_port("localhost:8080");
    if (argc == 3) {
        if (std::strcmp("--verbose", argv[1]) != 0)
            Usage();
        verbose = true;
        solr_host_and_port = argv[2];
    } else if (argc == 2) {
        if (std::strcmp("--verbose", argv[1]) == 0)
            verbose = true;
        else
            solr_host_and_port = argv[1];
    }

    try {
	std::string mysql_url;
	VuFind::GetMysqlURL(&mysql_url);
	DbConnection db_connection(mysql_url);

        ProcessSubscriptions(verbose, &db_connection, solr_host_and_port);
    } catch (const std::exception &x) {
	Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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 "details/IndirectLight.h"

#include "details/Engine.h"
#include "details/Texture.h"

#include "FilamentAPI-impl.h"

#include <utils/Panic.h>

#include <backend/DriverEnums.h>
#include <filament/IndirectLight.h>
#include <utils/Log.h>

#include <math/scalar.h>

#define IBL_INTEGRATION_PREFILTERED_CUBEMAP         0
#define IBL_INTEGRATION_IMPORTANCE_SAMPLING         1
#define IBL_INTEGRATION                             IBL_INTEGRATION_PREFILTERED_CUBEMAP

using namespace filament::math;

namespace filament {

using namespace details;

// ------------------------------------------------------------------------------------------------

struct IndirectLight::BuilderDetails {
    Texture const* mReflectionsMap = nullptr;
    Texture const* mIrradianceMap = nullptr;
    float3 mIrradianceCoefs[9] = {};
    mat3f mRotation = {};
    float mIntensity = 30000.0f;
};

using BuilderType = IndirectLight;
BuilderType::Builder::Builder() noexcept = default;
BuilderType::Builder::~Builder() noexcept = default;
BuilderType::Builder::Builder(BuilderType::Builder const& rhs) noexcept = default;
BuilderType::Builder::Builder(BuilderType::Builder&& rhs) noexcept = default;
BuilderType::Builder& BuilderType::Builder::operator=(BuilderType::Builder const& rhs) noexcept = default;
BuilderType::Builder& BuilderType::Builder::operator=(BuilderType::Builder&& rhs) noexcept = default;

IndirectLight::Builder& IndirectLight::Builder::reflections(Texture const* cubemap) noexcept {
    mImpl->mReflectionsMap = cubemap;
    return *this;
}

IndirectLight::Builder& IndirectLight::Builder::irradiance(uint8_t bands, float3 const* sh) noexcept {
    // clamp to 3 bands for now
    bands = std::min(bands, uint8_t(3));
    size_t numCoefs = bands * bands;
    std::fill(std::begin(mImpl->mIrradianceCoefs), std::end(mImpl->mIrradianceCoefs), 0.0f);
    std::copy_n(sh, numCoefs, std::begin(mImpl->mIrradianceCoefs));
    return *this;
}

IndirectLight::Builder& IndirectLight::Builder::radiance(uint8_t bands, float3 const* sh) noexcept {
    float3 irradiance[9];
    if (bands >= 1) {
        irradiance[0] = sh[0] * 0.282095f;
        if (bands >= 2) {
            irradiance[1] = sh[1] * -0.325735f;
            irradiance[2] = sh[2] *  0.325735f;
            irradiance[3] = sh[3] * -0.325735f;
            if (bands >= 3) {
                irradiance[4] = sh[4] *  0.273137f;
                irradiance[5] = sh[5] * -0.273137f;
                irradiance[6] = sh[6] *  0.078848f;
                irradiance[7] = sh[7] * -0.273137f;
                irradiance[8] = sh[8] *  0.136569f;
            }
        }
    }
    return this->irradiance(bands, irradiance);
}

IndirectLight::Builder& IndirectLight::Builder::irradiance(Texture const* cubemap) noexcept {
    mImpl->mIrradianceMap = cubemap;
    return *this;
}

IndirectLight::Builder& IndirectLight::Builder::intensity(float envIntensity) noexcept {
    mImpl->mIntensity = envIntensity;
    return *this;
}

IndirectLight::Builder& IndirectLight::Builder::rotation(mat3f const& rotation) noexcept {
    mImpl->mRotation = rotation;
    return *this;
}

IndirectLight* IndirectLight::Builder::build(Engine& engine) {
    if (mImpl->mReflectionsMap) {
        if (!ASSERT_POSTCONDITION_NON_FATAL(
                mImpl->mReflectionsMap->getTarget() == Texture::Sampler::SAMPLER_CUBEMAP,
                "reflection map must a cubemap")) {
            return nullptr;
        }

        if (!ASSERT_POSTCONDITION_NON_FATAL(mImpl->mReflectionsMap->getLevels() ==
                upcast(mImpl->mReflectionsMap)->getMaxLevelCount(),
                "reflection map must have %u mipmap levels",
                upcast(mImpl->mReflectionsMap)->getMaxLevelCount())) {
            return nullptr;
        }
        if (IBL_INTEGRATION == IBL_INTEGRATION_IMPORTANCE_SAMPLING) {
            mImpl->mReflectionsMap->generateMipmaps(engine);
        }
    }

    if (mImpl->mIrradianceMap) {
        if (!ASSERT_POSTCONDITION_NON_FATAL(
                mImpl->mIrradianceMap->getTarget() == Texture::Sampler::SAMPLER_CUBEMAP,
                "irradiance map must a cubemap")) {
            return nullptr;
        }
    }

    return upcast(engine).createIndirectLight(*this);
}

// ------------------------------------------------------------------------------------------------

namespace details {

FIndirectLight::FIndirectLight(FEngine& engine, const Builder& builder) noexcept {
    if (builder->mReflectionsMap) {
        mReflectionsMapHandle = upcast(builder->mReflectionsMap)->getHwHandle();
        mMaxMipLevel = builder->mReflectionsMap->getLevels();
    }

    std::copy(
            std::begin(builder->mIrradianceCoefs),
            std::end(builder->mIrradianceCoefs),
            mIrradianceCoefs.begin());

    mRotation = builder->mRotation;
    mIntensity = builder->mIntensity;
    if (builder->mIrradianceMap) {
        mIrradianceMapHandle = upcast(builder->mIrradianceMap)->getHwHandle();
    } else {
        // TODO: if needed, generate the irradiance map, this is an engine config
        if (FEngine::CONFIG_IBL_USE_IRRADIANCE_MAP) {
        }
    }
}

void FIndirectLight::terminate(FEngine& engine) {
    if (FEngine::CONFIG_IBL_USE_IRRADIANCE_MAP) {
        FEngine::DriverApi& driver = engine.getDriverApi();
        driver.destroyTexture(mIrradianceMapHandle);
    }
}

math::float3 FIndirectLight::getDirectionEstimate() const noexcept {
    auto const& f = mIrradianceCoefs;
    // The linear direction is found as normalize(-sh[3], -sh[1], sh[2]), but the coefficients
    // we store are already pre-normalized, so the negative sign disappears.
    // Note: we normalize the directions only after blending, this matches code used elsewhere --
    // the length of the vector is somewhat related to the intensity in that direction.
    float3 r = float3{ f[3].r, f[1].r, f[2].r };
    float3 g = float3{ f[3].g, f[1].g, f[2].g };
    float3 b = float3{ f[3].b, f[1].b, f[2].b };
    // We're assuming there is a single white light.
    return -normalize(r * 0.2126f + g * 0.7152f + b * 0.0722f);
}

float4 FIndirectLight::getColorEstimate(float3 direction) const noexcept {
    // See: https://www.gamasutra.com/view/news/129689/Indepth_Extracting_dominant_light_from_Spherical_Harmonics.php

    // first get the direction
    const float3 s = -direction;

    // The light intensity on one channel is given by: dot(Ld, Le) / dot(Ld, Ld)

    // our pre-convolved, pre-scaled SH coefficients for the environment
    auto const& Le = mIrradianceCoefs;

    // SH coefficients of the directional light pre-scaled by 1/A[i]
    // (we pre-scale by 1/A[i] to undo Le's pre-scaling by A[i]
    const float Ld[9] = {
            1.0f,
            s.y, s.z, s.x,
            s.y * s.x, s.y * s.z, (3 * s.z * s.z - 1), s.z * s.x, (s.x * s.x - s.y * s.y)
    };

    // dot(Ld, Le) -- notice that this is equivalent to "sampling" the sphere in the light
    // direction; this is the exact same code used in the shader for SH reconstruction.
    float3 LdDotLe = Ld[0] * Le[0]
                   + Ld[1] * Le[1] + Ld[2] * Le[2] + Ld[3] * Le[3]
                   + Ld[4] * Le[4] + Ld[5] * Le[5] + Ld[6] * Le[6] + Ld[7] * Le[7] + Ld[8] * Le[8];

    // The scale factor below is explained in the gamasutra article above, however it seems
    // to cause the intensity of the light to be too low.
    //      constexpr float c = (16.0f * M_PI / 17.0f);
    //      constexpr float LdSquared = (9.0f / (4.0f * M_PI)) * c * c;
    //      LdDotLe *= c / LdSquared; // Note the final coefficient is 17/36

    // We multiply by PI because our SH coefficients contain the 1/PI lambertian BRDF.
    LdDotLe *= M_PI;

    // Make sure we don't have negative intensities
    LdDotLe = max(LdDotLe, float3{0});

    const float intensity = max(LdDotLe);
    return { LdDotLe / intensity, intensity };
}

} // namespace details

// ------------------------------------------------------------------------------------------------
// Trampoline calling into private implementation
// ------------------------------------------------------------------------------------------------

void IndirectLight::setIntensity(float intensity) noexcept {
    upcast(this)->setIntensity(intensity);
}

float IndirectLight::getIntensity() const noexcept {
    return upcast(this)->getIntensity();
}

void IndirectLight::setRotation(mat3f const& rotation) noexcept {
    upcast(this)->setRotation(rotation);
}

const math::mat3f& IndirectLight::getRotation() const noexcept {
    return upcast(this)->getRotation();
}

math::float3 IndirectLight::getDirectionEstimate() const noexcept {
    return upcast(this)->getDirectionEstimate();
}

math::float4 IndirectLight::getColorEstimate(math::float3 direction) const noexcept {
    return upcast(this)->getColorEstimate(direction);
}

} // namespace filament
<commit_msg>don't use hard-coded values for Builder::radiance()<commit_after>/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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 "details/IndirectLight.h"

#include "details/Engine.h"
#include "details/Texture.h"

#include "FilamentAPI-impl.h"

#include <utils/Panic.h>

#include <backend/DriverEnums.h>
#include <filament/IndirectLight.h>
#include <utils/Log.h>

#include <math/scalar.h>

#define IBL_INTEGRATION_PREFILTERED_CUBEMAP         0
#define IBL_INTEGRATION_IMPORTANCE_SAMPLING         1
#define IBL_INTEGRATION                             IBL_INTEGRATION_PREFILTERED_CUBEMAP

using namespace filament::math;

namespace filament {

using namespace details;

// ------------------------------------------------------------------------------------------------

struct IndirectLight::BuilderDetails {
    Texture const* mReflectionsMap = nullptr;
    Texture const* mIrradianceMap = nullptr;
    float3 mIrradianceCoefs[9] = {};
    mat3f mRotation = {};
    float mIntensity = 30000.0f;
};

using BuilderType = IndirectLight;
BuilderType::Builder::Builder() noexcept = default;
BuilderType::Builder::~Builder() noexcept = default;
BuilderType::Builder::Builder(BuilderType::Builder const& rhs) noexcept = default;
BuilderType::Builder::Builder(BuilderType::Builder&& rhs) noexcept = default;
BuilderType::Builder& BuilderType::Builder::operator=(BuilderType::Builder const& rhs) noexcept = default;
BuilderType::Builder& BuilderType::Builder::operator=(BuilderType::Builder&& rhs) noexcept = default;

IndirectLight::Builder& IndirectLight::Builder::reflections(Texture const* cubemap) noexcept {
    mImpl->mReflectionsMap = cubemap;
    return *this;
}

IndirectLight::Builder& IndirectLight::Builder::irradiance(uint8_t bands, float3 const* sh) noexcept {
    // clamp to 3 bands for now
    bands = std::min(bands, uint8_t(3));
    size_t numCoefs = bands * bands;
    std::fill(std::begin(mImpl->mIrradianceCoefs), std::end(mImpl->mIrradianceCoefs), 0.0f);
    std::copy_n(sh, numCoefs, std::begin(mImpl->mIrradianceCoefs));
    return *this;
}

IndirectLight::Builder& IndirectLight::Builder::radiance(uint8_t bands, float3 const* sh) noexcept {
    // Coefficient for the polynomial form of the SH functions -- these were taken from
    // "Stupid Spherical Harmonics (SH)" by Peter-Pike Sloan
    // They simply come for expanding the computation of each SH function.
    //
    // To render spherical harmonics we can use the polynomial form, like this:
    //          c += sh[0] * A[0];
    //          c += sh[1] * A[1] * s.y;
    //          c += sh[2] * A[2] * s.z;
    //          c += sh[3] * A[3] * s.x;
    //          c += sh[4] * A[4] * s.y * s.x;
    //          c += sh[5] * A[5] * s.y * s.z;
    //          c += sh[6] * A[6] * (3 * s.z * s.z - 1);
    //          c += sh[7] * A[7] * s.z * s.x;
    //          c += sh[8] * A[8] * (s.x * s.x - s.y * s.y);
    //
    // To save math in the shader, we pre-multiply our SH coefficient by the A[i] factors.
    // Additionally, we include the lambertian diffuse BRDF 1/pi and truncated cos.

    constexpr float M_SQRT_PI = 1.7724538509f;
    constexpr float M_SQRT_3  = 1.7320508076f;
    constexpr float M_SQRT_5  = 2.2360679775f;
    constexpr float M_SQRT_15 = 3.8729833462f;
    constexpr float C[] = { M_PI, 2.0943951f, 0.785398f }; // <cos>
    constexpr float A[] = {
                  1.0f / (2.0f * M_SQRT_PI) * C[0] * M_1_PI,    // 0  0
            -M_SQRT_3  / (2.0f * M_SQRT_PI) * C[1] * M_1_PI,    // 1 -1
             M_SQRT_3  / (2.0f * M_SQRT_PI) * C[1] * M_1_PI,    // 1  0
            -M_SQRT_3  / (2.0f * M_SQRT_PI) * C[1] * M_1_PI,    // 1  1
             M_SQRT_15 / (2.0f * M_SQRT_PI) * C[2] * M_1_PI,    // 2 -2
            -M_SQRT_15 / (2.0f * M_SQRT_PI) * C[2] * M_1_PI,    // 3 -1
             M_SQRT_5  / (4.0f * M_SQRT_PI) * C[2] * M_1_PI,    // 3  0
            -M_SQRT_15 / (2.0f * M_SQRT_PI) * C[2] * M_1_PI,    // 3  1
             M_SQRT_15 / (4.0f * M_SQRT_PI) * C[2] * M_1_PI     // 3  2
    };

    // this is a way to "document" the actual value of these coefficients and at the same
    // time make sure the expression and values are always in sync.
    struct Debug {
        static constexpr bool almost(float a, float b) {
            constexpr float e = 1e-6f;
            return (a > b - e) && (a < b + e);
        }
    };
    static_assert(Debug::almost(A[0],  0.282095f), "coefficient mismatch");
    static_assert(Debug::almost(A[1], -0.325735f), "coefficient mismatch");
    static_assert(Debug::almost(A[2],  0.325735f), "coefficient mismatch");
    static_assert(Debug::almost(A[3], -0.325735f), "coefficient mismatch");
    static_assert(Debug::almost(A[4],  0.273137f), "coefficient mismatch");
    static_assert(Debug::almost(A[5], -0.273137f), "coefficient mismatch");
    static_assert(Debug::almost(A[6],  0.078848f), "coefficient mismatch");
    static_assert(Debug::almost(A[7], -0.273137f), "coefficient mismatch");
    static_assert(Debug::almost(A[8],  0.136569f), "coefficient mismatch");

    float3 irradiance[9];
    bands = std::min(bands, uint8_t(3));
    for (size_t i = 0, c = bands * bands; i<c; ++i) {
        irradiance[i] = sh[i] * A[i];
    }
    return this->irradiance(bands, irradiance);
}

IndirectLight::Builder& IndirectLight::Builder::irradiance(Texture const* cubemap) noexcept {
    mImpl->mIrradianceMap = cubemap;
    return *this;
}

IndirectLight::Builder& IndirectLight::Builder::intensity(float envIntensity) noexcept {
    mImpl->mIntensity = envIntensity;
    return *this;
}

IndirectLight::Builder& IndirectLight::Builder::rotation(mat3f const& rotation) noexcept {
    mImpl->mRotation = rotation;
    return *this;
}

IndirectLight* IndirectLight::Builder::build(Engine& engine) {
    if (mImpl->mReflectionsMap) {
        if (!ASSERT_POSTCONDITION_NON_FATAL(
                mImpl->mReflectionsMap->getTarget() == Texture::Sampler::SAMPLER_CUBEMAP,
                "reflection map must a cubemap")) {
            return nullptr;
        }

        if (!ASSERT_POSTCONDITION_NON_FATAL(mImpl->mReflectionsMap->getLevels() ==
                upcast(mImpl->mReflectionsMap)->getMaxLevelCount(),
                "reflection map must have %u mipmap levels",
                upcast(mImpl->mReflectionsMap)->getMaxLevelCount())) {
            return nullptr;
        }
        if (IBL_INTEGRATION == IBL_INTEGRATION_IMPORTANCE_SAMPLING) {
            mImpl->mReflectionsMap->generateMipmaps(engine);
        }
    }

    if (mImpl->mIrradianceMap) {
        if (!ASSERT_POSTCONDITION_NON_FATAL(
                mImpl->mIrradianceMap->getTarget() == Texture::Sampler::SAMPLER_CUBEMAP,
                "irradiance map must a cubemap")) {
            return nullptr;
        }
    }

    return upcast(engine).createIndirectLight(*this);
}

// ------------------------------------------------------------------------------------------------

namespace details {

FIndirectLight::FIndirectLight(FEngine& engine, const Builder& builder) noexcept {
    if (builder->mReflectionsMap) {
        mReflectionsMapHandle = upcast(builder->mReflectionsMap)->getHwHandle();
        mMaxMipLevel = builder->mReflectionsMap->getLevels();
    }

    std::copy(
            std::begin(builder->mIrradianceCoefs),
            std::end(builder->mIrradianceCoefs),
            mIrradianceCoefs.begin());

    mRotation = builder->mRotation;
    mIntensity = builder->mIntensity;
    if (builder->mIrradianceMap) {
        mIrradianceMapHandle = upcast(builder->mIrradianceMap)->getHwHandle();
    } else {
        // TODO: if needed, generate the irradiance map, this is an engine config
        if (FEngine::CONFIG_IBL_USE_IRRADIANCE_MAP) {
        }
    }
}

void FIndirectLight::terminate(FEngine& engine) {
    if (FEngine::CONFIG_IBL_USE_IRRADIANCE_MAP) {
        FEngine::DriverApi& driver = engine.getDriverApi();
        driver.destroyTexture(mIrradianceMapHandle);
    }
}

math::float3 FIndirectLight::getDirectionEstimate() const noexcept {
    auto const& f = mIrradianceCoefs;
    // The linear direction is found as normalize(-sh[3], -sh[1], sh[2]), but the coefficients
    // we store are already pre-normalized, so the negative sign disappears.
    // Note: we normalize the directions only after blending, this matches code used elsewhere --
    // the length of the vector is somewhat related to the intensity in that direction.
    float3 r = float3{ f[3].r, f[1].r, f[2].r };
    float3 g = float3{ f[3].g, f[1].g, f[2].g };
    float3 b = float3{ f[3].b, f[1].b, f[2].b };
    // We're assuming there is a single white light.
    return -normalize(r * 0.2126f + g * 0.7152f + b * 0.0722f);
}

float4 FIndirectLight::getColorEstimate(float3 direction) const noexcept {
    // See: https://www.gamasutra.com/view/news/129689/Indepth_Extracting_dominant_light_from_Spherical_Harmonics.php

    // first get the direction
    const float3 s = -direction;

    // The light intensity on one channel is given by: dot(Ld, Le) / dot(Ld, Ld)

    // our pre-convolved, pre-scaled SH coefficients for the environment
    auto const& Le = mIrradianceCoefs;

    // SH coefficients of the directional light pre-scaled by 1/A[i]
    // (we pre-scale by 1/A[i] to undo Le's pre-scaling by A[i]
    const float Ld[9] = {
            1.0f,
            s.y, s.z, s.x,
            s.y * s.x, s.y * s.z, (3 * s.z * s.z - 1), s.z * s.x, (s.x * s.x - s.y * s.y)
    };

    // dot(Ld, Le) -- notice that this is equivalent to "sampling" the sphere in the light
    // direction; this is the exact same code used in the shader for SH reconstruction.
    float3 LdDotLe = Ld[0] * Le[0]
                   + Ld[1] * Le[1] + Ld[2] * Le[2] + Ld[3] * Le[3]
                   + Ld[4] * Le[4] + Ld[5] * Le[5] + Ld[6] * Le[6] + Ld[7] * Le[7] + Ld[8] * Le[8];

    // The scale factor below is explained in the gamasutra article above, however it seems
    // to cause the intensity of the light to be too low.
    //      constexpr float c = (16.0f * M_PI / 17.0f);
    //      constexpr float LdSquared = (9.0f / (4.0f * M_PI)) * c * c;
    //      LdDotLe *= c / LdSquared; // Note the final coefficient is 17/36

    // We multiply by PI because our SH coefficients contain the 1/PI lambertian BRDF.
    LdDotLe *= M_PI;

    // Make sure we don't have negative intensities
    LdDotLe = max(LdDotLe, float3{0});

    const float intensity = max(LdDotLe);
    return { LdDotLe / intensity, intensity };
}

} // namespace details

// ------------------------------------------------------------------------------------------------
// Trampoline calling into private implementation
// ------------------------------------------------------------------------------------------------

void IndirectLight::setIntensity(float intensity) noexcept {
    upcast(this)->setIntensity(intensity);
}

float IndirectLight::getIntensity() const noexcept {
    return upcast(this)->getIntensity();
}

void IndirectLight::setRotation(mat3f const& rotation) noexcept {
    upcast(this)->setRotation(rotation);
}

const math::mat3f& IndirectLight::getRotation() const noexcept {
    return upcast(this)->getRotation();
}

math::float3 IndirectLight::getDirectionEstimate() const noexcept {
    return upcast(this)->getDirectionEstimate();
}

math::float4 IndirectLight::getColorEstimate(math::float3 direction) const noexcept {
    return upcast(this)->getColorEstimate(direction);
}

} // namespace filament
<|endoftext|>


<commit_before>//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

//
// osdep.cc
//
// Provide definition of library functions that are missing on various
// systems.  The only reason this is a .cc file rather than a .c file
// is so that it can include bochs.h.  Bochs.h includes all the required
// system headers, with appropriate #ifdefs for different compilers and
// platforms.
//

#include "bochs.h"

//////////////////////////////////////////////////////////////////////
// Missing library functions.  These should work on any platform
// that needs them.
//////////////////////////////////////////////////////////////////////

#if !BX_HAVE_SNPRINTF
/* if they don't have snprintf, just use sprintf */
int bx_snprintf (char *s, size_t maxlen, const char *format, ...)
{
  va_list arg;
  int done;

  va_start (arg, format);
  done = vsprintf (s, format, arg);
  va_end (arg);

  return done;
}
#endif  /* !BX_HAVE_SNPRINTF */

#if !BX_HAVE_STRTOULL
/* taken from glibc-2.2.2: strtod.c, and stripped down a lot.  There are
   still a few leftover references to decimal points and exponents,
   but it works for bases 10 and 16 */

#define RETURN(val,end)							      \
    do { if (endptr != NULL) *endptr = (char *) (end);		      \
	 return val; } while (0)

Bit64u
bx_strtoull (const char *nptr, char **endptr, int baseignore)
{
  int negative;			/* The sign of the number.  */
  int exponent;			/* Exponent of the number.  */

  /* Numbers starting `0X' or `0x' have to be processed with base 16.  */
  int base = 10;

  /* Number of bits currently in result value.  */
  int bits;

  /* Running pointer after the last character processed in the string.  */
  const char *cp, *tp;
  /* Start of significant part of the number.  */
  const char *startp, *start_of_digits;
  /* Total number of digit and number of digits in integer part.  */
  int dig_no;
  /* Contains the last character read.  */
  char c;

  long long n = 0;
  char const *p;

  /* Prepare number representation.  */
  exponent = 0;
  negative = 0;
  bits = 0;

  /* Parse string to get maximal legal prefix.  We need the number of
     characters of the integer part, the fractional part and the exponent.  */
  cp = nptr - 1;
  /* Ignore leading white space.  */
  do
    c = *++cp;
  while (isspace (c));

  /* Get sign of the result.  */
  if (c == '-')
    {
      negative = 1;
      c = *++cp;
    }
  else if (c == '+')
    c = *++cp;

  if (c < '0' || c > '9')
    {
      /* It is really a text we do not recognize.  */
      RETURN (0, nptr);
    }

  /* First look whether we are faced with a hexadecimal number.  */
  if (c == '0' && tolower (cp[1]) == 'x')
    {
      /* Okay, it is a hexa-decimal number.  Remember this and skip
	 the characters.  BTW: hexadecimal numbers must not be
	 grouped.  */
      base = 16;
      cp += 2;
      c = *cp;
    }

  /* Record the start of the digits, in case we will check their grouping.  */
  start_of_digits = startp = cp;

  /* Ignore leading zeroes.  This helps us to avoid useless computations.  */
  while (c == '0')
    c = *++cp;

  /* If no other digit but a '0' is found the result is 0.0.
     Return current read pointer.  */
  if ((c < '0' || c > '9')
      && (base == 16 && (c < tolower ('a') || c > tolower ('f')))
      && (base == 16 && (cp == start_of_digits || tolower (c) != 'p'))
      && (base != 16 && tolower (c) != 'e'))
    {
      tp = start_of_digits;
      /* If TP is at the start of the digits, there was no correctly
	 grouped prefix of the string; so no number found.  */
      RETURN (0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
    }

  /* Remember first significant digit and read following characters until the
     decimal point, exponent character or any non-FP number character.  */
  startp = cp;
  dig_no = 0;
  while (1)
    {
      if ((c >= '0' && c <= '9')
	  || (base == 16 && tolower (c) >= 'a' && tolower (c) <= 'f'))
	++dig_no;
      else
	break;
      c = *++cp;
    }

  /* The whole string is parsed.  Store the address of the next character.  */
  if (endptr)
    *endptr = (char *) cp;

  if (dig_no == 0)
    return 0;

  for (p=start_of_digits; p!=cp; p++) {
    n = n * (long long)base;
    c = tolower (*p);
    c = (c >= 'a') ? (10+c-'a') : c-'0';
    n = n + (long long)c;
    //printf ("after shifting in digit %c, n is %lld\n", *p, n);
  }
  return negative? -n : n;
}
#endif  /* !BX_HAVE_STRTOULL */

#if BX_TEST_STRTOULL_MAIN
/* test driver for strtoull.  Do not compile by default. */
int main (int argc, char **argv)
{
  char buf[256], *endbuf;
  long l;
  long long ll;
  while (1) {
    printf ("Enter a long int: ");
    gets (buf);
    l = strtoul (buf, &endbuf, 10);
    printf ("As a long, %ld\n", l);
    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
    ll = bx_strtoull (buf, &endbuf, 10);
    printf ("As a long long, %lld\n", ll);
    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
  }
  return 0;
}
#endif  /* BX_TEST_STRTOULL_MAIN */

#if !BX_HAVE_STRDUP
char *bx_strdup(const char *str)
{
	char *temp;

	temp = malloc(strlen(str));
	sprintf(temp, "%s", str);
	return temp;

	// Well, I'm sure this isn't how strdup is REALLY implemented,
	// but it works...
}
#endif  /* !BX_HAVE_STRDUP */

//////////////////////////////////////////////////////////////////////
// Missing library functions, implemented for MacOS only
//////////////////////////////////////////////////////////////////////

#if BX_WITH_MACOS
// these functions are part of MacBochs.  They are not intended to be
// portable!
#include <Files.h>
#include <Disks.h>

int fd_read(char *buffer, Bit32u offset, Bit32u bytes)
{
	OSErr err;
	IOParam param;

	param.ioRefNum=-5; // Refnum of the floppy disk driver
	param.ioVRefNum=1;
	param.ioPosMode=fsFromStart;
	param.ioPosOffset=offset;
	param.ioBuffer=buffer;
	param.ioReqCount=bytes;
	err = PBReadSync((union ParamBlockRec *)(&param));
	return param.ioActCount;
}

int fd_write(char *buffer, Bit32u offset, Bit32u bytes)
{
	OSErr		err;
	IOParam	param;

	param.ioRefNum=-5; // Refnum of the floppy disk driver
	param.ioVRefNum=1;
	param.ioPosMode=fsFromStart;
	param.ioPosOffset=offset;
	param.ioBuffer=buffer;
	param.ioReqCount=bytes;
	err = PBWriteSync((union ParamBlockRec *)(&param));
	return param.ioActCount;
}

int fd_stat(struct stat *buf)
{
	OSErr		err;
	DrvSts	status;
	int			result;

	result = 0;
	err = DriveStatus(1, &status);
	if (status.diskInPlace <1 || status.diskInPlace > 2)
		result = -1;
	buf->st_mode = S_IFCHR;
	return result;
}
#endif /* BX_WITH_MACOS */
<commit_msg>total revisions: 5;	selected revisions: 5 description:<commit_after>#include "bochs.h"

#if !BX_HAVE_SNPRINTF
/* if they don't have snprintf, just use sprintf */
int bx_snprintf (char *s, size_t maxlen, const char *format, ...)
{
  va_list arg;
  int done;

  va_start (arg, format);
  done = vsprintf (s, format, arg);
  va_end (arg);

  return done;
}
#endif  /* !BX_HAVE_SNPRINTF */

#if !BX_HAVE_STRTOULL
/* taken from glibc-2.2.2: strtod.c, and stripped down a lot.  There are
   still a few leftover references to decimal points and exponents,
   but it seems to work for bases 10 and 16 */

#define RETURN(val,end)							      \
    do { if (endptr != NULL) *endptr = (char *) (end);		      \
	 return val; } while (0)

unsigned long long bx_strtoull
(const char *nptr, char **endptr, int baseignore)
{
  int negative;			/* The sign of the number.  */
  int exponent;			/* Exponent of the number.  */

  /* Numbers starting `0X' or `0x' have to be processed with base 16.  */
  int base = 10;

  /* Number of bits currently in result value.  */
  int bits;

  /* Running pointer after the last character processed in the string.  */
  const char *cp, *tp;
  /* Start of significant part of the number.  */
  const char *startp, *start_of_digits;
  /* Total number of digit and number of digits in integer part.  */
  int dig_no;
  /* Contains the last character read.  */
  char c;

  long long n = 0;
  char const *p;

  /* Prepare number representation.  */
  exponent = 0;
  negative = 0;
  bits = 0;

  /* Parse string to get maximal legal prefix.  We need the number of
     characters of the integer part, the fractional part and the exponent.  */
  cp = nptr - 1;
  /* Ignore leading white space.  */
  do
    c = *++cp;
  while (isspace (c));

  /* Get sign of the result.  */
  if (c == '-')
    {
      negative = 1;
      c = *++cp;
    }
  else if (c == '+')
    c = *++cp;

  if (c < '0' || c > '9')
    {
      /* It is really a text we do not recognize.  */
      RETURN (0, nptr);
    }

  /* First look whether we are faced with a hexadecimal number.  */
  if (c == '0' && tolower (cp[1]) == 'x')
    {
      /* Okay, it is a hexa-decimal number.  Remember this and skip
	 the characters.  BTW: hexadecimal numbers must not be
	 grouped.  */
      base = 16;
      cp += 2;
      c = *cp;
    }

  /* Record the start of the digits, in case we will check their grouping.  */
  start_of_digits = startp = cp;

  /* Ignore leading zeroes.  This helps us to avoid useless computations.  */
  while (c == '0')
    c = *++cp;

  /* If no other digit but a '0' is found the result is 0.0.
     Return current read pointer.  */
  if ((c < '0' || c > '9')
      && (base == 16 && (c < tolower ('a') || c > tolower ('f')))
      && (base == 16 && (cp == start_of_digits || tolower (c) != 'p'))
      && (base != 16 && tolower (c) != 'e'))
    {
      tp = start_of_digits;
      /* If TP is at the start of the digits, there was no correctly
	 grouped prefix of the string; so no number found.  */
      RETURN (0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
    }

  /* Remember first significant digit and read following characters until the
     decimal point, exponent character or any non-FP number character.  */
  startp = cp;
  dig_no = 0;
  while (1)
    {
      if ((c >= '0' && c <= '9')
	  || (base == 16 && tolower (c) >= 'a' && tolower (c) <= 'f'))
	++dig_no;
      else
	break;
      c = *++cp;
    }

  /* The whole string is parsed.  Store the address of the next character.  */
  if (endptr)
    *endptr = (char *) cp;

  if (dig_no == 0)
    return 0;

  for (p=start_of_digits; p!=cp; p++) {
    n = n * (long long)base;
    c = tolower (*p);
    c = (c >= 'a') ? (10+c-'a') : c-'0';
    n = n + (long long)c;
    //printf ("after shifting in digit %c, n is %lld\n", *p, n);
  }
  return negative? -n : n;
}

#if BX_TEST_STRTOULL
/* test driver for strtoull */
int main (int argc, char **argv)
{
  char buf[256], *endbuf;
  long l;
  long long ll;
  while (1) {
    printf ("Enter a long int: ");
    gets (buf);
    l = strtoul (buf, &endbuf, 10);
    printf ("As a long, %ld\n", l);
    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
    ll = bx_strtoull (buf, &endbuf, 10);
    printf ("As a long long, %lld\n", ll);
    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
  }
  return 0;
}
#endif  /* defined BX_TEST_STRTOULL */

#endif  /* !BX_HAVE_STRTOULL */
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2015 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdio.h>
#include <sstream>
#include "value.h"
#include "array.h"
#include "object.h"

using namespace dvbtee::decode;

ValueBase::ValueBase(const std::type_info& type, std::string name)
 : m_type(type)
 , m_name(name)
 , m_refcnt(0)
{
}

ValueBase &ValueBase::operator++()
{
	m_refcnt++;
	return *this;
}

ValueBase &ValueBase::operator--()
{
	m_refcnt--;
	return *this;
}

ValueBase::~ValueBase()
{
}

const std::type_info& ValueBase::getType() const
{
	return m_type;
}

const std::string& ValueBase::getName() const
{
	return m_name;
}

const int &ValueBase::getRefCnt() const
{
	return m_refcnt;
}

const bool ValueBase::checkType(const std::type_info& typeRequested) const
{
	const bool ret = (typeRequested == m_type);
	if (!ret) fprintf(stderr, "Incorrect type requested for %s, requested %s, should be %s\n", m_name.length() ? m_name.c_str() : "[anonymous]", typeRequested.name(), typeid(m_type).name());
	return ret;
}

const std::string ValueBase::toJson() const
{
	std::stringstream s;

	     if (m_type == typeid(int))			s << ((Value<int>*)this)->get();
	else if (m_type == typeid(long))		s << ((Value<long>*)this)->get();
	else if (m_type == typeid(unsigned short))	s << ((Value<unsigned short>*)this)->get();
	else if (m_type == typeid(unsigned char))	s << (unsigned int)((Value<unsigned char>*)this)->get();
	else if (m_type == typeid(std::string))		s << "'" << ((Value<std::string>*)this)->get() << "'";
	else if (m_type == typeid(bool))		s << (((Value<bool>*)this)->get() ? "true" : "false");
	else if (m_type == typeid(double))		s << ((Value<double>*)this)->get();
	else if (m_type == typeid(Object))		s << ((Value<Object>*)this)->get().toJson().c_str();
	else if (m_type == typeid(Array))		s << ((Value<Array>*)this)->get().toJson().c_str();
	else if (m_type == typeid(time_t))		s << (unsigned long)((Value<time_t>*)this)->get();
	else if (m_type == typeid(size_t))		s << (unsigned long)((Value<time_t>*)this)->get();
	else if (m_type == typeid(void))		s << ((ValueUndefined*)this)->get();
	// else // FIXME

	if (s.str().length())
		return s.str();

	return "undefined";
}

ValueUndefined::ValueUndefined(std::string n)
	: ValueBase(typeid(void), n)
{
}

ValueUndefined::ValueUndefined(const ValueUndefined &v)
	: ValueBase(typeid(void), v.getName())
{
}

ValueUndefined::~ValueUndefined()
{
}

const std::string ValueUndefined::get() const
{
	return "undefined";
}
<commit_msg>value: CalueBase::toJson: fix typo in handling of size_t type<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2015 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdio.h>
#include <sstream>
#include "value.h"
#include "array.h"
#include "object.h"

using namespace dvbtee::decode;

ValueBase::ValueBase(const std::type_info& type, std::string name)
 : m_type(type)
 , m_name(name)
 , m_refcnt(0)
{
}

ValueBase &ValueBase::operator++()
{
	m_refcnt++;
	return *this;
}

ValueBase &ValueBase::operator--()
{
	m_refcnt--;
	return *this;
}

ValueBase::~ValueBase()
{
}

const std::type_info& ValueBase::getType() const
{
	return m_type;
}

const std::string& ValueBase::getName() const
{
	return m_name;
}

const int &ValueBase::getRefCnt() const
{
	return m_refcnt;
}

const bool ValueBase::checkType(const std::type_info& typeRequested) const
{
	const bool ret = (typeRequested == m_type);
	if (!ret) fprintf(stderr, "Incorrect type requested for %s, requested %s, should be %s\n", m_name.length() ? m_name.c_str() : "[anonymous]", typeRequested.name(), typeid(m_type).name());
	return ret;
}

const std::string ValueBase::toJson() const
{
	std::stringstream s;

	     if (m_type == typeid(int))			s << ((Value<int>*)this)->get();
	else if (m_type == typeid(long))		s << ((Value<long>*)this)->get();
	else if (m_type == typeid(unsigned short))	s << ((Value<unsigned short>*)this)->get();
	else if (m_type == typeid(unsigned char))	s << (unsigned int)((Value<unsigned char>*)this)->get();
	else if (m_type == typeid(std::string))		s << "'" << ((Value<std::string>*)this)->get() << "'";
	else if (m_type == typeid(bool))		s << (((Value<bool>*)this)->get() ? "true" : "false");
	else if (m_type == typeid(double))		s << ((Value<double>*)this)->get();
	else if (m_type == typeid(Object))		s << ((Value<Object>*)this)->get().toJson().c_str();
	else if (m_type == typeid(Array))		s << ((Value<Array>*)this)->get().toJson().c_str();
	else if (m_type == typeid(time_t))		s << (unsigned long)((Value<time_t>*)this)->get();
	else if (m_type == typeid(size_t))		s << (unsigned long)((Value<size_t>*)this)->get();
	else if (m_type == typeid(void))		s << ((ValueUndefined*)this)->get();
	// else // FIXME

	if (s.str().length())
		return s.str();

	return "undefined";
}

ValueUndefined::ValueUndefined(std::string n)
	: ValueBase(typeid(void), n)
{
}

ValueUndefined::ValueUndefined(const ValueUndefined &v)
	: ValueBase(typeid(void), v.getName())
{
}

ValueUndefined::~ValueUndefined()
{
}

const std::string ValueUndefined::get() const
{
	return "undefined";
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2015 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdio.h>
#include <sstream>
#include "value.h"
#include "array.h"
#include "object.h"

using namespace dvbtee::decode;

ValueBase::ValueBase(const std::type_info& type, std::string name)
 : m_type(type)
 , m_name(name)
{
}

ValueBase::~ValueBase()
{
}

const std::type_info& ValueBase::getType()
{
	return m_type;
}

const std::string& ValueBase::getName()
{
	return m_name;
}

bool ValueBase::checkType(const std::type_info& typeRequested)
{
	bool ret = (typeRequested == m_type);
	if (!ret) fprintf(stderr, "Incorrect type requested for %s, requested %s, should be %s\n", m_name.length() ? m_name.c_str() : "[anonymous]", typeRequested.name(), typeid(m_type).name());
	return ret;
}

const std::string ValueBase::toJson()
{
	std::stringstream s;

	     if (m_type == typeid(int))			s << ((Value<int>*)this)->get();
	else if (m_type == typeid(unsigned short))	s << ((Value<unsigned short>*)this)->get();
	else if (m_type == typeid(unsigned char))	s << (unsigned int)((Value<unsigned char>*)this)->get();
	else if (m_type == typeid(std::string))		s << "'" << ((Value<std::string>*)this)->get() << "'";
	else if (m_type == typeid(bool))		s << (((Value<bool>*)this)->get() ? "true" : "false");
	else if (m_type == typeid(double))		s << ((Value<double>*)this)->get();
	else if (m_type == typeid(Object))		s << ((Value<Object>*)this)->get().toJson().c_str();
	else if (m_type == typeid(Array))		s << ((Value<Array>*)this)->get().toJson().c_str();
	else if (m_type == typeid(time_t))		s << (unsigned long)((Value<time_t>*)this)->get();
	else if (m_type == typeid(size_t))		s << (unsigned long)((Value<time_t>*)this)->get();

	return s.str();
}
<commit_msg>decode/value: display errors as undefined values<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2015 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdio.h>
#include <sstream>
#include "value.h"
#include "array.h"
#include "object.h"

using namespace dvbtee::decode;

ValueBase::ValueBase(const std::type_info& type, std::string name)
 : m_type(type)
 , m_name(name)
{
}

ValueBase::~ValueBase()
{
}

const std::type_info& ValueBase::getType()
{
	return m_type;
}

const std::string& ValueBase::getName()
{
	return m_name;
}

bool ValueBase::checkType(const std::type_info& typeRequested)
{
	bool ret = (typeRequested == m_type);
	if (!ret) fprintf(stderr, "Incorrect type requested for %s, requested %s, should be %s\n", m_name.length() ? m_name.c_str() : "[anonymous]", typeRequested.name(), typeid(m_type).name());
	return ret;
}

const std::string ValueBase::toJson()
{
	std::stringstream s;

	     if (m_type == typeid(int))			s << ((Value<int>*)this)->get();
	else if (m_type == typeid(unsigned short))	s << ((Value<unsigned short>*)this)->get();
	else if (m_type == typeid(unsigned char))	s << (unsigned int)((Value<unsigned char>*)this)->get();
	else if (m_type == typeid(std::string))		s << "'" << ((Value<std::string>*)this)->get() << "'";
	else if (m_type == typeid(bool))		s << (((Value<bool>*)this)->get() ? "true" : "false");
	else if (m_type == typeid(double))		s << ((Value<double>*)this)->get();
	else if (m_type == typeid(Object))		s << ((Value<Object>*)this)->get().toJson().c_str();
	else if (m_type == typeid(Array))		s << ((Value<Array>*)this)->get().toJson().c_str();
	else if (m_type == typeid(time_t))		s << (unsigned long)((Value<time_t>*)this)->get();
	else if (m_type == typeid(size_t))		s << (unsigned long)((Value<time_t>*)this)->get();

	if (s.str().length())
		return s.str();

	return "undefined";
}
<|endoftext|>