<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  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
//
//  Current versions can be found at www.libavg.de
//

#include "GeomHelper.h"

#include <math.h>
#include <iostream>

using namespace std;

namespace avg {

DLineSegment::DLineSegment(const DPoint& pt0, const DPoint& pt1)
    : p0(pt0),
      p1(pt1)
{
}

bool DLineSegment::isPointOver(const DPoint& pt)
{
    DPoint c = pt - p0;   // DPoint from a to Point
    DPoint v = (p1 - p0);
    double d = v.getNorm(); // Length of the line segment
    v /= d; // Unit DPoint from a to b
    double t = dotProduct(v, c);  // Intersection point Distance from a

    return (t >= 0 && t <= d);
}

// Code adapted from Antonio, Franklin, "Faster Line Segment Intersection,"
// Graphics Gems III (David Kirk, ed.), Academic Press, pp. 199-202, 1992.
bool lineSegmentsIntersect(const DLineSegment& l0, const DLineSegment& l1)
{
    double xdiff0 = l0.p1.x-l0.p0.x;
    double xdiff1 = l1.p0.x-l1.p1.x;

    double x1lo, x1hi;

    /* X bound box test*/
    if (xdiff0 < 0) {
        x1lo=l0.p1.x;
        x1hi=l0.p0.x;
    } else {
        x1hi=l0.p1.x;
        x1lo=l0.p0.x;
    }
    if (xdiff1>0) {
        if (x1hi < l1.p1.x || l1.p0.x < x1lo) {
            return false;
        }
    } else {
        if (x1hi < l1.p0.x || l1.p1.x < x1lo) {
            return false;
        }
    }

    double ydiff0 = l0.p1.y-l0.p0.y;
    double ydiff1 = l1.p0.y-l1.p1.y;

    double y1lo, y1hi;

    /* Y bound box test*/
    if (ydiff0<0) {
        y1lo=l0.p1.y;
        y1hi=l0.p0.y;
    } else {
        y1hi=l0.p1.y;
        y1lo=l0.p0.y;
    }
    if (ydiff1>0) {
        if (y1hi < l1.p1.y || l1.p0.y < y1lo) {
            return false;
        }
    } else {
        if (y1hi < l1.p0.y || l1.p1.y < y1lo) {
            return false;
        }
    }

    double Cx = l0.p0.x-l1.p0.x;
    double Cy = l0.p0.y-l1.p0.y;
    double d = ydiff1*Cx - xdiff1*Cy;                  /* alpha numerator*/
    double f = ydiff0*xdiff1 - xdiff0*ydiff1;          /* both denominator*/
    if (f>0) {                                         /* alpha tests*/
        if (d<0 || d>f) {
            return false;
        }
    } else {
        if (d>0 || d<f) {
            return false;
        }
    }

    double e = xdiff0*Cy - ydiff0*Cx;                  /* beta numerator*/
    if(f>0) {                                          /* beta tests*/
        if (e<0 || e>f) {
            return false;
        }
    } else {
        if (e>0 || e<f) {
            return false;
        }
    }

    if (f==0) {
        // Theoretically, lines could still intersect in this case, but we don't care
        // because given numerical inaccuracies, the result is random anyway :-).
        return false;
    }

//    /*compute intersection coordinates*/
//    double num = d*xdiff0;                     /* numerator */
//    offset = SAME_SIGNS(num,f) ? f/2 : -f/2;   /* round direction*/
//    *x = x1 + (num+offset) / f;                /* intersection x */
//
//    num = d*ydiff0;
//    offset = SAME_SIGNS(num,f) ? f/2 : -f/2;
//    *y = y1 + (num+offset) / f;                /* intersection y */

    return true;
}

// Standard Jordan Curve Theorem (aka ray casting, even-odd-rule, crossing number)
// point-in-polygon test.
// Precomputing a bounding box for the polygon would speed this up a lot,
// but we're not using the code in a speed-critical place so far.
bool pointInPolygon(const DPoint& pt, const vector<DPoint>& poly)
{
    if (poly.size() < 3) {
        return false;
    }
    DPoint pointOutside(0,0);
    vector<DPoint>::const_iterator it;
    for (it=poly.begin(); it != poly.end(); ++it) {
        if (pointOutside.x > it->x) {
            pointOutside = *it;
        }
    }
    pointOutside.x -= 1;

    DLineSegment line0(pointOutside, pt);
    const DPoint* pLastPt = &(*--poly.end());
    bool ptInPoly = false;
    for (it=poly.begin(); it != poly.end(); ++it) {
        DLineSegment line1(*pLastPt, *it);
        if (lineSegmentsIntersect(line0, line1)) {
            ptInPoly = !ptInPoly;
        }
        pLastPt = &(*it);
    }
    return ptInPoly;
}

DPoint getLineLineIntersection(const DPoint& p1, const DPoint& v1, const DPoint& p2,
        const DPoint& v2)
{
    double denom = v2.y*v1.x-v2.x*v1.y;
    if (fabs(denom) < 0.0000001) {
        // If the lines are parallel or coincident, we just return p2!
        return p2;
    }
    double numer = v2.x*(p1.y-p2.y) - v2.y*(p1.x-p2.x);
    double ua = numer/denom;

    return p1+ua*v1;

}

}
<commit_msg>Replaced point in polygon algorithm to fix bug (when the intersection ray passes through a vertex of the polygon, the result was random).<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  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
//
//  Current versions can be found at www.libavg.de
//

#include "GeomHelper.h"

#include <math.h>
#include <iostream>

using namespace std;

namespace avg {

DLineSegment::DLineSegment(const DPoint& pt0, const DPoint& pt1)
    : p0(pt0),
      p1(pt1)
{
}

bool DLineSegment::isPointOver(const DPoint& pt)
{
    DPoint c = pt - p0;   // DPoint from a to Point
    DPoint v = (p1 - p0);
    double d = v.getNorm(); // Length of the line segment
    v /= d; // Unit DPoint from a to b
    double t = dotProduct(v, c);  // Intersection point Distance from a

    return (t >= 0 && t <= d);
}

// Code adapted from Antonio, Franklin, "Faster Line Segment Intersection,"
// Graphics Gems III (David Kirk, ed.), Academic Press, pp. 199-202, 1992.
bool lineSegmentsIntersect(const DLineSegment& l0, const DLineSegment& l1)
{
    double xdiff0 = l0.p1.x-l0.p0.x;
    double xdiff1 = l1.p0.x-l1.p1.x;

    double x1lo, x1hi;

    /* X bound box test*/
    if (xdiff0 < 0) {
        x1lo=l0.p1.x;
        x1hi=l0.p0.x;
    } else {
        x1hi=l0.p1.x;
        x1lo=l0.p0.x;
    }
    if (xdiff1>0) {
        if (x1hi < l1.p1.x || l1.p0.x < x1lo) {
            return false;
        }
    } else {
        if (x1hi < l1.p0.x || l1.p1.x < x1lo) {
            return false;
        }
    }

    double ydiff0 = l0.p1.y-l0.p0.y;
    double ydiff1 = l1.p0.y-l1.p1.y;

    double y1lo, y1hi;

    /* Y bound box test*/
    if (ydiff0<0) {
        y1lo=l0.p1.y;
        y1hi=l0.p0.y;
    } else {
        y1hi=l0.p1.y;
        y1lo=l0.p0.y;
    }
    if (ydiff1>0) {
        if (y1hi < l1.p1.y || l1.p0.y < y1lo) {
            return false;
        }
    } else {
        if (y1hi < l1.p0.y || l1.p1.y < y1lo) {
            return false;
        }
    }

    double Cx = l0.p0.x-l1.p0.x;
    double Cy = l0.p0.y-l1.p0.y;
    double d = ydiff1*Cx - xdiff1*Cy;                  /* alpha numerator*/
    double f = ydiff0*xdiff1 - xdiff0*ydiff1;          /* both denominator*/
    if (f>0) {                                         /* alpha tests*/
        if (d<0 || d>f) {
            return false;
        }
    } else {
        if (d>0 || d<f) {
            return false;
        }
    }

    double e = xdiff0*Cy - ydiff0*Cx;                  /* beta numerator*/
    if(f>0) {                                          /* beta tests*/
        if (e<0 || e>f) {
            return false;
        }
    } else {
        if (e>0 || e<f) {
            return false;
        }
    }

    if (f==0) {
        // Theoretically, lines could still intersect in this case, but we don't care
        // because given numerical inaccuracies, the result is random anyway :-).
        return false;
    }

//    /*compute intersection coordinates*/
//    double num = d*xdiff0;                     /* numerator */
//    offset = SAME_SIGNS(num,f) ? f/2 : -f/2;   /* round direction*/
//    *x = x1 + (num+offset) / f;                /* intersection x */
//
//    num = d*ydiff0;
//    offset = SAME_SIGNS(num,f) ? f/2 : -f/2;
//    *y = y1 + (num+offset) / f;                /* intersection y */

    return true;
}

// Original code from: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html.
// Precomputing a bounding box for the polygon would speed this up a lot,
// but it hasn't shown up on any profiles so far.
bool pointInPolygon(const DPoint& pt, const vector<DPoint>& poly)
{
    if (poly.size() < 3) {
        return false;
    }
    bool bPtInPoly = false;
    for (unsigned i = 0, j = poly.size()-1; i < poly.size(); j = i++) {
        if (((poly[i].y > pt.y) != (poly[j].y > pt.y)) &&
                (pt.x < (poly[j].x-poly[i].x)*(pt.y-poly[i].y) / (poly[j].y-poly[i].y)
                 +poly[i].x))
        {
            bPtInPoly = !bPtInPoly;
        }
    }
    return bPtInPoly;
}

DPoint getLineLineIntersection(const DPoint& p1, const DPoint& v1, const DPoint& p2,
        const DPoint& v2)
{
    double denom = v2.y*v1.x-v2.x*v1.y;
    if (fabs(denom) < 0.0000001) {
        // If the lines are parallel or coincident, we just return p2!
        return p2;
    }
    double numer = v2.x*(p1.y-p2.y) - v2.y*(p1.x-p2.x);
    double ua = numer/denom;

    return p1+ua*v1;

}

}
<|endoftext|>


<commit_before>/*
 * Copyright 2019 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "tools/SkSharingProc.h"

#include "include/core/SkData.h"
#include "include/core/SkImage.h"
#include "include/core/SkSerialProcs.h"

sk_sp<SkData> SkSharingSerialContext::serializeImage(SkImage* img, void* ctx) {
    SkSharingSerialContext* context = reinterpret_cast<SkSharingSerialContext*>(ctx);
    uint32_t id = img->uniqueID(); // get this process's id for the image. these are not hashes.
    // find out if we have already serialized this, and if so, what its in-file id is.
    auto iter = context->fImageMap.find(id);
    if (iter == context->fImageMap.end()) {
        // When not present, add its id to the map and return its usual serialized form.
        context->fImageMap[id] = context->fImageMap.size();
        return img->encodeToData();
    }
    uint32_t fid = context->fImageMap[id];
    // if present, return only the in-file id we registered the first time we serialized it.
    return SkData::MakeWithCopy(&fid, sizeof(fid));
}

sk_sp<SkImage> SkSharingDeserialContext::deserializeImage(
  const void* data, size_t length, void* ctx) {
    SkSharingDeserialContext* context = reinterpret_cast<SkSharingDeserialContext*>(ctx);
    uint32_t fid;
    // If the data is an image fid, look up an already deserialized image from our map
    if (length == sizeof(fid)) {
        memcpy(&fid, data, sizeof(fid));
        if (fid >= context->fImages.size()) {
            SkDebugf("We do not have the data for image %d.\n", fid);
            return nullptr;
        }
        return context->fImages[fid];
    }
    // Otherwise, the data is an image, deserialise it, store it in our map at its fid.
    // TODO(nifong): make DeserialProcs accept sk_sp<SkData> so we don't have to copy this.
    sk_sp<SkData> dataView = SkData::MakeWithCopy(data, length);
    const sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(dataView));
    context->fImages.push_back(image);
    return image;
}
<commit_msg>Don't crash debugger on missing images<commit_after>/*
 * Copyright 2019 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "tools/SkSharingProc.h"

#include "include/core/SkBitmap.h"
#include "include/core/SkData.h"
#include "include/core/SkImage.h"
#include "include/core/SkSerialProcs.h"

sk_sp<SkData> SkSharingSerialContext::serializeImage(SkImage* img, void* ctx) {
    SkSharingSerialContext* context = reinterpret_cast<SkSharingSerialContext*>(ctx);
    uint32_t id = img->uniqueID(); // get this process's id for the image. these are not hashes.
    // find out if we have already serialized this, and if so, what its in-file id is.
    auto iter = context->fImageMap.find(id);
    if (iter == context->fImageMap.end()) {
        // When not present, add its id to the map and return its usual serialized form.
        context->fImageMap[id] = context->fImageMap.size();
        return img->encodeToData();
    }
    uint32_t fid = context->fImageMap[id];
    // if present, return only the in-file id we registered the first time we serialized it.
    return SkData::MakeWithCopy(&fid, sizeof(fid));
}

sk_sp<SkImage> SkSharingDeserialContext::deserializeImage(
  const void* data, size_t length, void* ctx) {
    if (!data || !length || !ctx) {
        SkDebugf("SkSharingDeserialContext::deserializeImage arguments invalid %p %d %p.\n",
            data, length, ctx);
        // Return something so the rest of the debugger can proceeed.
        SkBitmap bm;
        bm.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
        return SkImage::MakeFromBitmap(bm);
    }
    SkSharingDeserialContext* context = reinterpret_cast<SkSharingDeserialContext*>(ctx);
    uint32_t fid;
    // If the data is an image fid, look up an already deserialized image from our map
    if (length == sizeof(fid)) {
        memcpy(&fid, data, sizeof(fid));
        if (fid >= context->fImages.size()) {
            SkDebugf("We do not have the data for image %d.\n", fid);
            return nullptr;
        }
        return context->fImages[fid];
    }
    // Otherwise, the data is an image, deserialise it, store it in our map at its fid.
    // TODO(nifong): make DeserialProcs accept sk_sp<SkData> so we don't have to copy this.
    sk_sp<SkData> dataView = SkData::MakeWithCopy(data, length);
    const sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(dataView));
    context->fImages.push_back(image);
    return image;
}
<|endoftext|>


<commit_before>#include <cstring>
#include <cstdlib>

#include <sys/un.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "dinit.h"
#include "dinit-log.h"
#include "dinit-socket.h"
#include "proc-service.h"

#include "baseproc-sys.h"

/*
 * Base process implementation (base_process_service).
 *
 * See proc-service.h for interface documentation.
 */

void base_process_service::do_smooth_recovery() noexcept
{
    if (! restart_ps_process()) {
        emergency_stop();
        services->process_queues();
    }
}

bool base_process_service::bring_up() noexcept
{
    if (restarting) {
        if (pid == -1) {
            return restart_ps_process();
        }
        return true;
    }
    else {
        if (! open_socket()) {
            return false;
        }

        restart_interval_count = 0;
        if (start_ps_process(exec_arg_parts,
                onstart_flags.starts_on_console || onstart_flags.shares_console)) {
            // start_ps_process updates last_start_time, use it also for restart_interval_time:
            restart_interval_time = last_start_time;
            // Note: we don't set a start timeout for PROCESS services.
            if (start_timeout != time_val(0,0) && get_type() != service_type_t::PROCESS) {
                restart_timer.arm_timer_rel(event_loop, start_timeout);
                stop_timer_armed = true;
            }
            else if (stop_timer_armed) {
                restart_timer.stop_timer(event_loop);
                stop_timer_armed = false;
            }
            return true;
        }
        restart_interval_time = last_start_time;
        return false;
    }
}

bool base_process_service::start_ps_process(const std::vector<const char *> &cmd, bool on_console) noexcept
{
    // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
    // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
    // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
    // is written to the pipe, and the parent can read it.

    event_loop.get_time(last_start_time, clock_type::MONOTONIC);

    int pipefd[2];
    if (bp_sys::pipe2(pipefd, O_CLOEXEC)) {
        log(loglevel_t::ERROR, get_name(), ": can't create status check pipe: ", strerror(errno));
        return false;
    }

    const char * logfile = this->logfile.c_str();
    if (*logfile == 0) {
        logfile = "/dev/null";
    }

    bool child_status_registered = false;
    control_conn_t *control_conn = nullptr;

    int control_socket[2] = {-1, -1};
    if (onstart_flags.pass_cs_fd) {
        if (dinit_socketpair(AF_UNIX, SOCK_STREAM, /* protocol */ 0, control_socket, SOCK_NONBLOCK)) {
            log(loglevel_t::ERROR, get_name(), ": can't create control socket: ", strerror(errno));
            goto out_p;
        }

        // Make the server side socket close-on-exec:
        int fdflags = bp_sys::fcntl(control_socket[0], F_GETFD);
        bp_sys::fcntl(control_socket[0], F_SETFD, fdflags | FD_CLOEXEC);

        try {
            control_conn = new control_conn_t(event_loop, services, control_socket[0]);
        }
        catch (std::exception &exc) {
            log(loglevel_t::ERROR, get_name(), ": can't launch process; out of memory");
            goto out_cs;
        }
    }

    // Set up complete, now fork and exec:

    pid_t forkpid;

    try {
        child_status_listener.add_watch(event_loop, pipefd[0], dasynq::IN_EVENTS);
        child_status_registered = true;

        // We specify a high priority (i.e. low priority value) so that process termination is
        // handled early. This means we have always recorded that the process is terminated by the
        // time that we handle events that might otherwise cause us to signal the process, so we
        // avoid sending a signal to an invalid (and possibly recycled) process ID.
        forkpid = child_listener.fork(event_loop, reserved_child_watch, dasynq::DEFAULT_PRIORITY - 10);
        reserved_child_watch = true;
    }
    catch (std::exception &e) {
        log(loglevel_t::ERROR, get_name(), ": Could not fork: ", e.what());
        goto out_cs_h;
    }

    if (forkpid == 0) {
        const char * working_dir_c = nullptr;
        if (! working_dir.empty()) working_dir_c = working_dir.c_str();
        run_child_proc(cmd.data(), working_dir_c, logfile, on_console, pipefd[1], control_socket[1],
                socket_fd, run_as_uid, run_as_gid);
    }
    else {
        // Parent process
        bp_sys::close(pipefd[1]); // close the 'other end' fd
        if (control_socket[1] != -1) {
            bp_sys::close(control_socket[1]);
        }
        pid = forkpid;

        waiting_for_execstat = true;
        return true;
    }

    // Failure exit:

    out_cs_h:
    if (child_status_registered) {
        child_status_listener.deregister(event_loop);
    }

    if (onstart_flags.pass_cs_fd) {
        delete control_conn;

        out_cs:
        bp_sys::close(control_socket[0]);
        bp_sys::close(control_socket[1]);
    }

    out_p:
    bp_sys::close(pipefd[0]);
    bp_sys::close(pipefd[1]);

    return false;
}

base_process_service::base_process_service(service_set *sset, string name,
        service_type_t service_type_p, string &&command,
        const std::list<std::pair<unsigned,unsigned>> &command_offsets,
        const std::list<prelim_dep> &deplist_p)
     : service_record(sset, name, service_type_p, deplist_p), child_listener(this),
       child_status_listener(this), restart_timer(this)
{
    program_name = std::move(command);
    exec_arg_parts = separate_args(program_name, command_offsets);

    restart_interval_count = 0;
    restart_interval_time = {0, 0};
    restart_timer.service = this;
    restart_timer.add_timer(event_loop);

    // By default, allow a maximum of 3 restarts within 10.0 seconds:
    restart_interval.seconds() = 10;
    restart_interval.nseconds() = 0;
    max_restart_interval_count = 3;

    waiting_restart_timer = false;
    reserved_child_watch = false;
    tracking_child = false;
    stop_timer_armed = false;
}

void base_process_service::do_restart() noexcept
{
    waiting_restart_timer = false;
    restart_interval_count++;
    auto service_state = get_state();

    if (service_state == service_state_t::STARTING) {
        // for a smooth recovery, we want to check dependencies are available before actually
        // starting:
        if (! check_deps_started()) {
            waiting_for_deps = true;
            return;
        }
    }

    if (! start_ps_process(exec_arg_parts, have_console || onstart_flags.shares_console)) {
        restarting = false;
        if (service_state == service_state_t::STARTING) {
            failed_to_start();
        }
        else {
            // desired_state = service_state_t::STOPPED;
            forced_stop();
        }
        services->process_queues();
    }
}

bool base_process_service::restart_ps_process() noexcept
{
    using time_val = dasynq::time_val;

    time_val current_time;
    event_loop.get_time(current_time, clock_type::MONOTONIC);

    if (max_restart_interval_count != 0) {
        // Check whether we're still in the most recent restart check interval:
        time_val int_diff = current_time - restart_interval_time;
        if (int_diff < restart_interval) {
            if (restart_interval_count >= max_restart_interval_count) {
                log(loglevel_t::ERROR, "Service ", get_name(), " restarting too quickly; stopping.");
                return false;
            }
        }
        else {
            restart_interval_time = current_time;
            restart_interval_count = 0;
        }
    }

    // Check if enough time has lapsed since the previous restart. If not, start a timer:
    time_val tdiff = current_time - last_start_time;
    if (restart_delay <= tdiff) {
        // > restart delay (normally 200ms)
        do_restart();
    }
    else {
        time_val timeout = restart_delay - tdiff;
        restart_timer.arm_timer_rel(event_loop, timeout);
        waiting_restart_timer = true;
    }
    return true;
}

bool base_process_service::interrupt_start() noexcept
{
    if (waiting_restart_timer) {
        restart_timer.stop_timer(event_loop);
        waiting_restart_timer = false;
        return service_record::interrupt_start();
    }
    else {
        log(loglevel_t::WARN, "Interrupting start of service ", get_name(), " with pid ", pid, " (with SIGINT).");
        kill_pg(SIGINT);

        if (stop_timeout != time_val(0,0)) {
            restart_timer.arm_timer_rel(event_loop, stop_timeout);
            stop_timer_armed = true;
        }
        else if (stop_timer_armed) {
            restart_timer.stop_timer(event_loop);
            stop_timer_armed = false;
        }

        set_state(service_state_t::STOPPING);
        return false;
    }
}

void base_process_service::kill_with_fire() noexcept
{
    if (pid != -1) {
        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed stop time; killing.");
        kill_pg(SIGKILL);
    }
}

void base_process_service::kill_pg(int signo) noexcept
{
    if (onstart_flags.signal_process_only) {
        bp_sys::kill(pid, signo);
    }
    else {
        pid_t pgid = bp_sys::getpgid(pid);
        if (pgid == -1) {
            // only should happen if pid is invalid, which should never happen...
            log(loglevel_t::ERROR, get_name(), ": can't signal process: ", strerror(errno));
            return;
        }
        bp_sys::kill(-pgid, signo);
    }
}

void base_process_service::timer_expired() noexcept
{
    stop_timer_armed = false;

    // Timer expires if:
    // We are stopping, including after having startup cancelled (stop timeout, state is STOPPING); We are
    // starting (start timeout, state is STARTING); We are waiting for restart timer before restarting,
    // including smooth recovery (restart timeout, state is STARTING or STARTED).
    if (get_state() == service_state_t::STOPPING) {
        kill_with_fire();
    }
    else if (pid != -1) {
        // Starting, start timed out.
        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed start time; cancelling.");
        interrupt_start();
        stop_reason = stopped_reason_t::TIMEDOUT;
        failed_to_start(false, false);
    }
    else {
        // STARTING / STARTED, and we have a pid: must be restarting (smooth recovery if STARTED)
        do_restart();
    }
}

void base_process_service::emergency_stop() noexcept
{
    if (! do_auto_restart() && start_explicit) {
        start_explicit = false;
        release(false);
    }
    forced_stop();
    stop_dependents();
}

void base_process_service::becoming_inactive() noexcept
{
    if (socket_fd != -1) {
        close(socket_fd);
        socket_fd = -1;
    }
}

bool base_process_service::open_socket() noexcept
{
    if (socket_path.empty() || socket_fd != -1) {
        // No socket, or already open
        return true;
    }

    const char * saddrname = socket_path.c_str();

    // Check the specified socket path
    struct stat stat_buf;
    if (stat(saddrname, &stat_buf) == 0) {
        if ((stat_buf.st_mode & S_IFSOCK) == 0) {
            // Not a socket
            log(loglevel_t::ERROR, get_name(), ": Activation socket file exists (and is not a socket)");
            return false;
        }
    }
    else if (errno != ENOENT) {
        // Other error
        log(loglevel_t::ERROR, get_name(), ": Error checking activation socket: ", strerror(errno));
        return false;
    }

    // Remove stale socket file (if it exists).
    // We won't test the return from unlink - if it fails other than due to ENOENT, we should get an
    // error when we try to create the socket anyway.
    unlink(saddrname);

    uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + socket_path.length() + 1;
    struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
    if (name == nullptr) {
        log(loglevel_t::ERROR, get_name(), ": Opening activation socket: out of memory");
        return false;
    }

    name->sun_family = AF_UNIX;
    strcpy(name->sun_path, saddrname);

    int sockfd = dinit_socket(AF_UNIX, SOCK_STREAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
    if (sockfd == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error creating activation socket: ", strerror(errno));
        free(name);
        return false;
    }

    if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error binding activation socket: ", strerror(errno));
        close(sockfd);
        free(name);
        return false;
    }

    free(name);

    // POSIX (1003.1, 2013) says that fchown and fchmod don't necessarily work on sockets. We have to
    // use chown and chmod instead.
    if (chown(saddrname, socket_uid, socket_gid)) {
        log(loglevel_t::ERROR, get_name(), ": Error setting activation socket owner/group: ", strerror(errno));
        close(sockfd);
        return false;
    }

    if (chmod(saddrname, socket_perms) == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error setting activation socket permissions: ", strerror(errno));
        close(sockfd);
        return false;
    }

    if (listen(sockfd, 128) == -1) { // 128 "seems reasonable".
        log(loglevel_t::ERROR, ": Error listening on activation socket: ", strerror(errno));
        close(sockfd);
        return false;
    }

    socket_fd = sockfd;
    return true;
}
<commit_msg>Shorten (wrap) some too-long lines.<commit_after>#include <cstring>
#include <cstdlib>

#include <sys/un.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "dinit.h"
#include "dinit-log.h"
#include "dinit-socket.h"
#include "proc-service.h"

#include "baseproc-sys.h"

/*
 * Base process implementation (base_process_service).
 *
 * See proc-service.h for interface documentation.
 */

void base_process_service::do_smooth_recovery() noexcept
{
    if (! restart_ps_process()) {
        emergency_stop();
        services->process_queues();
    }
}

bool base_process_service::bring_up() noexcept
{
    if (restarting) {
        if (pid == -1) {
            return restart_ps_process();
        }
        return true;
    }
    else {
        if (! open_socket()) {
            return false;
        }

        restart_interval_count = 0;
        if (start_ps_process(exec_arg_parts,
                onstart_flags.starts_on_console || onstart_flags.shares_console)) {
            // start_ps_process updates last_start_time, use it also for restart_interval_time:
            restart_interval_time = last_start_time;
            // Note: we don't set a start timeout for PROCESS services.
            if (start_timeout != time_val(0,0) && get_type() != service_type_t::PROCESS) {
                restart_timer.arm_timer_rel(event_loop, start_timeout);
                stop_timer_armed = true;
            }
            else if (stop_timer_armed) {
                restart_timer.stop_timer(event_loop);
                stop_timer_armed = false;
            }
            return true;
        }
        restart_interval_time = last_start_time;
        return false;
    }
}

bool base_process_service::start_ps_process(const std::vector<const char *> &cmd, bool on_console) noexcept
{
    // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
    // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
    // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
    // is written to the pipe, and the parent can read it.

    event_loop.get_time(last_start_time, clock_type::MONOTONIC);

    int pipefd[2];
    if (bp_sys::pipe2(pipefd, O_CLOEXEC)) {
        log(loglevel_t::ERROR, get_name(), ": can't create status check pipe: ", strerror(errno));
        return false;
    }

    const char * logfile = this->logfile.c_str();
    if (*logfile == 0) {
        logfile = "/dev/null";
    }

    bool child_status_registered = false;
    control_conn_t *control_conn = nullptr;

    int control_socket[2] = {-1, -1};
    if (onstart_flags.pass_cs_fd) {
        if (dinit_socketpair(AF_UNIX, SOCK_STREAM, /* protocol */ 0, control_socket, SOCK_NONBLOCK)) {
            log(loglevel_t::ERROR, get_name(), ": can't create control socket: ", strerror(errno));
            goto out_p;
        }

        // Make the server side socket close-on-exec:
        int fdflags = bp_sys::fcntl(control_socket[0], F_GETFD);
        bp_sys::fcntl(control_socket[0], F_SETFD, fdflags | FD_CLOEXEC);

        try {
            control_conn = new control_conn_t(event_loop, services, control_socket[0]);
        }
        catch (std::exception &exc) {
            log(loglevel_t::ERROR, get_name(), ": can't launch process; out of memory");
            goto out_cs;
        }
    }

    // Set up complete, now fork and exec:

    pid_t forkpid;

    try {
        child_status_listener.add_watch(event_loop, pipefd[0], dasynq::IN_EVENTS);
        child_status_registered = true;

        // We specify a high priority (i.e. low priority value) so that process termination is
        // handled early. This means we have always recorded that the process is terminated by the
        // time that we handle events that might otherwise cause us to signal the process, so we
        // avoid sending a signal to an invalid (and possibly recycled) process ID.
        forkpid = child_listener.fork(event_loop, reserved_child_watch, dasynq::DEFAULT_PRIORITY - 10);
        reserved_child_watch = true;
    }
    catch (std::exception &e) {
        log(loglevel_t::ERROR, get_name(), ": Could not fork: ", e.what());
        goto out_cs_h;
    }

    if (forkpid == 0) {
        const char * working_dir_c = nullptr;
        if (! working_dir.empty()) working_dir_c = working_dir.c_str();
        run_child_proc(cmd.data(), working_dir_c, logfile, on_console, pipefd[1], control_socket[1],
                socket_fd, run_as_uid, run_as_gid);
    }
    else {
        // Parent process
        bp_sys::close(pipefd[1]); // close the 'other end' fd
        if (control_socket[1] != -1) {
            bp_sys::close(control_socket[1]);
        }
        pid = forkpid;

        waiting_for_execstat = true;
        return true;
    }

    // Failure exit:

    out_cs_h:
    if (child_status_registered) {
        child_status_listener.deregister(event_loop);
    }

    if (onstart_flags.pass_cs_fd) {
        delete control_conn;

        out_cs:
        bp_sys::close(control_socket[0]);
        bp_sys::close(control_socket[1]);
    }

    out_p:
    bp_sys::close(pipefd[0]);
    bp_sys::close(pipefd[1]);

    return false;
}

base_process_service::base_process_service(service_set *sset, string name,
        service_type_t service_type_p, string &&command,
        const std::list<std::pair<unsigned,unsigned>> &command_offsets,
        const std::list<prelim_dep> &deplist_p)
     : service_record(sset, name, service_type_p, deplist_p), child_listener(this),
       child_status_listener(this), restart_timer(this)
{
    program_name = std::move(command);
    exec_arg_parts = separate_args(program_name, command_offsets);

    restart_interval_count = 0;
    restart_interval_time = {0, 0};
    restart_timer.service = this;
    restart_timer.add_timer(event_loop);

    // By default, allow a maximum of 3 restarts within 10.0 seconds:
    restart_interval.seconds() = 10;
    restart_interval.nseconds() = 0;
    max_restart_interval_count = 3;

    waiting_restart_timer = false;
    reserved_child_watch = false;
    tracking_child = false;
    stop_timer_armed = false;
}

void base_process_service::do_restart() noexcept
{
    waiting_restart_timer = false;
    restart_interval_count++;
    auto service_state = get_state();

    if (service_state == service_state_t::STARTING) {
        // for a smooth recovery, we want to check dependencies are available before actually
        // starting:
        if (! check_deps_started()) {
            waiting_for_deps = true;
            return;
        }
    }

    if (! start_ps_process(exec_arg_parts, have_console || onstart_flags.shares_console)) {
        restarting = false;
        if (service_state == service_state_t::STARTING) {
            failed_to_start();
        }
        else {
            // desired_state = service_state_t::STOPPED;
            forced_stop();
        }
        services->process_queues();
    }
}

bool base_process_service::restart_ps_process() noexcept
{
    using time_val = dasynq::time_val;

    time_val current_time;
    event_loop.get_time(current_time, clock_type::MONOTONIC);

    if (max_restart_interval_count != 0) {
        // Check whether we're still in the most recent restart check interval:
        time_val int_diff = current_time - restart_interval_time;
        if (int_diff < restart_interval) {
            if (restart_interval_count >= max_restart_interval_count) {
                log(loglevel_t::ERROR, "Service ", get_name(), " restarting too quickly; stopping.");
                return false;
            }
        }
        else {
            restart_interval_time = current_time;
            restart_interval_count = 0;
        }
    }

    // Check if enough time has lapsed since the previous restart. If not, start a timer:
    time_val tdiff = current_time - last_start_time;
    if (restart_delay <= tdiff) {
        // > restart delay (normally 200ms)
        do_restart();
    }
    else {
        time_val timeout = restart_delay - tdiff;
        restart_timer.arm_timer_rel(event_loop, timeout);
        waiting_restart_timer = true;
    }
    return true;
}

bool base_process_service::interrupt_start() noexcept
{
    if (waiting_restart_timer) {
        restart_timer.stop_timer(event_loop);
        waiting_restart_timer = false;
        return service_record::interrupt_start();
    }
    else {
        log(loglevel_t::WARN, "Interrupting start of service ", get_name(), " with pid ", pid,
                " (with SIGINT).");
        kill_pg(SIGINT);

        if (stop_timeout != time_val(0,0)) {
            restart_timer.arm_timer_rel(event_loop, stop_timeout);
            stop_timer_armed = true;
        }
        else if (stop_timer_armed) {
            restart_timer.stop_timer(event_loop);
            stop_timer_armed = false;
        }

        set_state(service_state_t::STOPPING);
        return false;
    }
}

void base_process_service::kill_with_fire() noexcept
{
    if (pid != -1) {
        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid,
                " exceeded allowed stop time; killing.");
        kill_pg(SIGKILL);
    }
}

void base_process_service::kill_pg(int signo) noexcept
{
    if (onstart_flags.signal_process_only) {
        bp_sys::kill(pid, signo);
    }
    else {
        pid_t pgid = bp_sys::getpgid(pid);
        if (pgid == -1) {
            // only should happen if pid is invalid, which should never happen...
            log(loglevel_t::ERROR, get_name(), ": can't signal process: ", strerror(errno));
            return;
        }
        bp_sys::kill(-pgid, signo);
    }
}

void base_process_service::timer_expired() noexcept
{
    stop_timer_armed = false;

    // Timer expires if:
    // We are stopping, including after having startup cancelled (stop timeout, state is STOPPING); We are
    // starting (start timeout, state is STARTING); We are waiting for restart timer before restarting,
    // including smooth recovery (restart timeout, state is STARTING or STARTED).
    if (get_state() == service_state_t::STOPPING) {
        kill_with_fire();
    }
    else if (pid != -1) {
        // Starting, start timed out.
        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid,
                " exceeded allowed start time; cancelling.");
        interrupt_start();
        stop_reason = stopped_reason_t::TIMEDOUT;
        failed_to_start(false, false);
    }
    else {
        // STARTING / STARTED, and we have a pid: must be restarting (smooth recovery if STARTED)
        do_restart();
    }
}

void base_process_service::emergency_stop() noexcept
{
    if (! do_auto_restart() && start_explicit) {
        start_explicit = false;
        release(false);
    }
    forced_stop();
    stop_dependents();
}

void base_process_service::becoming_inactive() noexcept
{
    if (socket_fd != -1) {
        close(socket_fd);
        socket_fd = -1;
    }
}

bool base_process_service::open_socket() noexcept
{
    if (socket_path.empty() || socket_fd != -1) {
        // No socket, or already open
        return true;
    }

    const char * saddrname = socket_path.c_str();

    // Check the specified socket path
    struct stat stat_buf;
    if (stat(saddrname, &stat_buf) == 0) {
        if ((stat_buf.st_mode & S_IFSOCK) == 0) {
            // Not a socket
            log(loglevel_t::ERROR, get_name(), ": Activation socket file exists (and is not a socket)");
            return false;
        }
    }
    else if (errno != ENOENT) {
        // Other error
        log(loglevel_t::ERROR, get_name(), ": Error checking activation socket: ", strerror(errno));
        return false;
    }

    // Remove stale socket file (if it exists).
    // We won't test the return from unlink - if it fails other than due to ENOENT, we should get an
    // error when we try to create the socket anyway.
    unlink(saddrname);

    uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + socket_path.length() + 1;
    struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
    if (name == nullptr) {
        log(loglevel_t::ERROR, get_name(), ": Opening activation socket: out of memory");
        return false;
    }

    name->sun_family = AF_UNIX;
    strcpy(name->sun_path, saddrname);

    int sockfd = dinit_socket(AF_UNIX, SOCK_STREAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
    if (sockfd == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error creating activation socket: ", strerror(errno));
        free(name);
        return false;
    }

    if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error binding activation socket: ", strerror(errno));
        close(sockfd);
        free(name);
        return false;
    }

    free(name);

    // POSIX (1003.1, 2013) says that fchown and fchmod don't necessarily work on sockets. We have to
    // use chown and chmod instead.
    if (chown(saddrname, socket_uid, socket_gid)) {
        log(loglevel_t::ERROR, get_name(), ": Error setting activation socket owner/group: ",
                strerror(errno));
        close(sockfd);
        return false;
    }

    if (chmod(saddrname, socket_perms) == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error setting activation socket permissions: ",
                strerror(errno));
        close(sockfd);
        return false;
    }

    if (listen(sockfd, 128) == -1) { // 128 "seems reasonable".
        log(loglevel_t::ERROR, ": Error listening on activation socket: ", strerror(errno));
        close(sockfd);
        return false;
    }

    socket_fd = sockfd;
    return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Sjors Gielen, 2010-2012
 * See LICENSE for license.
 */

#include "utils.h"

std::string strToLower(const std::string &f) {
	std::string res;
	res.reserve(f.length());
	for(unsigned i = 0; i < f.length(); ++i) {
		res.push_back(tolower(f[i]));
	}
	return res;
}

std::string strToUpper(const std::string &f) {
	std::string res;
	res.reserve(f.length());
	for(unsigned i = 0; i < f.length(); ++i) {
		res.push_back(toupper(f[i]));
	}
	return res;
}

std::string strToIdentifier(const std::string &f) {
	std::string res;
	res.reserve(f.length());
	for(unsigned i = 0; i < f.length(); ++i) {
		if(!isalpha(f[i])) continue;
		res.push_back(tolower(f[i]));
	}
	return res;
}

std::string trim(const std::string &s) {
	std::string str;
	bool alpha = true;
	for(unsigned i = 0; i < s.length(); ++i) {
		if(alpha && isalpha(s[i]))
			continue;
		alpha = false;
		str += s[i];
	}
	for(int i = str.length() - 1; i >= 0; --i) {
		if(isalpha(str[i]))
			str.resize(i);
		else break;
	}
	return str;
}

bool contains(std::string x, char v) {
	return find(x.begin(), x.end(), v) != x.end();
}

bool startsWith(std::string x, std::string y, bool caseInsensitive)
{
	std::string z = x.substr(0, y.length());
	if(caseInsensitive)
		return strToLower(z) == strToLower(y);
	else	return z == y;
}

std::vector<std::string> split(const std::string &s, const std::string &sep)
{
	std::vector<std::string> res;
	std::string s_ = s;
	int len = sep.length();
	int remaining = s.length();
	for(int i = 0; i <= remaining - len; ++i) {
		if(s_.substr(i, len) == sep) {
			res.push_back(s_.substr(0, i));
			s_ = s_.substr(i + sep.length());
			remaining -= i + sep.length();
			i = -1;
		}
	}
	res.push_back(s_);
	return res;
}

std::vector<std::string> &operator<<(std::vector<std::string> &x, const char *v) {
	x << std::string(v);
	return x;
}

std::vector<std::string>::iterator find_ci(std::vector<std::string> &v, const std::string &s) {
	std::string sl = strToLower(s);
	std::vector<std::string>::iterator it;
	for(it = v.begin(); it != v.end(); ++it) {
		if(strToLower(*it) == sl) {
			return it;
		}
	}
	return v.end();
}

<commit_msg>Forwardport dazeus/dazeus@4c7a33a069e2a12a7d0081a0f6a99b6a57ca43db to utils.cpp of libdazeus-irc.<commit_after>/*
 * Copyright (c) Sjors Gielen, 2010-2012
 * See LICENSE for license.
 */

#include "utils.h"

std::string strToLower(const std::string &f) {
	std::string res;
	res.reserve(f.length());
	for(unsigned i = 0; i < f.length(); ++i) {
		res.push_back(tolower(f[i]));
	}
	return res;
}

std::string strToUpper(const std::string &f) {
	std::string res;
	res.reserve(f.length());
	for(unsigned i = 0; i < f.length(); ++i) {
		res.push_back(toupper(f[i]));
	}
	return res;
}

std::string strToIdentifier(const std::string &f) {
	std::string res;
	res.reserve(f.length());
	for(unsigned i = 0; i < f.length(); ++i) {
		if(!isalpha(f[i])) continue;
		res.push_back(tolower(f[i]));
	}
	return res;
}

std::string trim(const std::string &s) {
	std::string str;
	bool alpha = true;
	for(unsigned i = 0; i < s.length(); ++i) {
		if(alpha && isspace(s[i]))
			continue;
		alpha = false;
		str += s[i];
	}
	for(int i = str.length() - 1; i >= 0; --i) {
		if(isspace(str[i]))
			str.resize(i);
		else break;
	}
	return str;
}

bool contains(std::string x, char v) {
	return find(x.begin(), x.end(), v) != x.end();
}

bool startsWith(std::string x, std::string y, bool caseInsensitive)
{
	std::string z = x.substr(0, y.length());
	if(caseInsensitive)
		return strToLower(z) == strToLower(y);
	else	return z == y;
}

std::vector<std::string> split(const std::string &s, const std::string &sep)
{
	std::vector<std::string> res;
	std::string s_ = s;
	int len = sep.length();
	int remaining = s.length();
	for(int i = 0; i <= remaining - len; ++i) {
		if(s_.substr(i, len) == sep) {
			res.push_back(s_.substr(0, i));
			s_ = s_.substr(i + sep.length());
			remaining -= i + sep.length();
			i = -1;
		}
	}
	res.push_back(s_);
	return res;
}

std::vector<std::string> &operator<<(std::vector<std::string> &x, const char *v) {
	x << std::string(v);
	return x;
}

std::vector<std::string>::iterator find_ci(std::vector<std::string> &v, const std::string &s) {
	std::string sl = strToLower(s);
	std::vector<std::string>::iterator it;
	for(it = v.begin(); it != v.end(); ++it) {
		if(strToLower(*it) == sl) {
			return it;
		}
	}
	return v.end();
}

<|endoftext|>


<commit_before>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
	// Global settings.
	ofSetWindowTitle("Presenter");
	ofSetVerticalSync(true);
	ofEnableSmoothing();
	ofSetFrameRate(60);

	// Position the window in the centre of the screen.
	ofSetWindowPosition((ofGetScreenWidth() - ofGetWindowWidth()) / 2, (ofGetScreenHeight() - ofGetWindowHeight()) / 2);

	// Set status to Welcome screen.
	status = PRESENTER_STATUS_WELCOME;

	// Load logo for welcome screen.
	logo.loadImage("logo.png");
	if(logo.getWidth()>550){
		logo.resize(550, logo.getHeight() / logo.getWidth() * 550);
	}

	// Create presentation chooser buttons.
	gui = new ofxUICanvas();
	gui->setPosition(650, 250);
	gui->setDrawBack(false);

	// Setup custom theme for GUI.
	ofxUIColor cb = ofxUIColor(38, 147, 255, 200);
    ofxUIColor co = ofxUIColor(38, 147, 255, 255);
    ofxUIColor coh = OFX_UI_COLOR_OUTLINE_HIGHLIGHT;
    ofxUIColor cf = ofxUIColor(255, 255, 255, 255);
    ofxUIColor cfh = OFX_UI_COLOR_FILL_HIGHLIGHT;
    ofxUIColor cp = ofxUIColor(38, 147, 255, 255);
    ofxUIColor cpo = OFX_UI_COLOR_PADDED_OUTLINE;
    gui->setUIColors( cb, co, coh, cf, cfh, cp, cpo );

	gui->addLabel("Select a presentation:", OFX_UI_FONT_MEDIUM)->setColorFill(ofxUIColor(0, 0, 0, 255));
    gui->addSpacer();

	// Each directory in bin/data/Presentations is concidered a presentation.
	int i, size;
	ofDirectory presentations;
	presentations = ofDirectory("Presentations");
	presentations.sort();
	presentations.listDir();
	size = presentations.size();

	for (i = 0; i < size; i++){
		if (presentations.getFile(i).isDirectory()==1){
			gui->addLabelButton(presentations.getFile(i).getFileName(), false, 300, 30, 0, 0, true);
		}
	}

    gui->autoSizeToFitWidgets();
    ofAddListener(gui->newGUIEvent,this,&ofApp::guiEvent);

	// Create shutdown button.
	shutdown = new ofxUICanvas();
	shutdown->setPosition(ofGetWindowWidth()-60, 10);
	shutdown->setDrawBack(false);

	shutdown->setGlobalButtonDimension(44);
	shutdown->addImageButton("Shutdown", "shutdown.png", false);
	shutdown->autoSizeToFitWidgets();
    ofAddListener(shutdown->newGUIEvent,this,&ofApp::guiEvent);

}

//--------------------------------------------------------------
void ofApp::update(){
	if(status == PRESENTER_STATUS_WELCOME){

	} else if (status == PRESENTER_STATUS_PRESENTATION){
		if(presentation != NULL){
			presentation->update();
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
	if(status == PRESENTER_STATUS_WELCOME){
		ofBackground(ofColor::white);
		logo.draw(50,75);
	} else if (status == PRESENTER_STATUS_PRESENTATION){
		if(presentation != NULL){
			presentation->draw();
		}
	}
}

void ofApp::guiEvent(ofxUIEventArgs &e)
{
	string name = e.widget->getName();
	int kind = e.widget->getKind();

    if(kind == OFX_UI_WIDGET_LABELBUTTON)
    {
        ofxUIButton *button = (ofxUIButton *) e.widget;
		if(!button->getValue()){
			// load presentation xml file.
			presentation = new Presentation(name);

			// set the status and hide the gui on welcome screen.
			status = PRESENTER_STATUS_PRESENTATION;
			ofHideCursor();
			gui->setVisible(false);
			shutdown->setVisible(false);

			cout << name << "\t value: " << button->getValue() << endl;
		}
    }
    else if(kind == OFX_UI_WIDGET_IMAGEBUTTON)
    {
        ofxUIImageButton *button = (ofxUIImageButton *) e.widget;
        if(button->getValue()){

#if defined(TARGET_RASPBERRY_PI)
			// On Raspberry Pi, shutdown.
			std::system("sudo shutdown -h now");
#else
			// Desktop applications, close the application.
			std::exit(0);
#endif

		}
    }
}

//--------------------------------------------------------------
void ofApp::exit()
{
    delete gui;
}

void ofApp::endPresentation(){
	status = PRESENTER_STATUS_WELCOME;
	ofShowCursor();
	gui->setVisible(true);
	shutdown->setVisible(true);
	delete presentation;
	presentation = NULL;
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key)
{
    switch (key)
    {
        case 'g':
            gui->toggleVisible();
			break;
		case OF_KEY_RIGHT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->next()==0){
					endPresentation();
				}
			}
            break;
		case OF_KEY_LEFT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->previous()==0){
					endPresentation();
				}
			}
            break;
        default:
            break;
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
	switch (button)
    {
		case OF_MOUSE_BUTTON_LEFT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->next()==0){
					endPresentation();
				}
			}
            break;
		case OF_MOUSE_BUTTON_RIGHT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->previous()==0){
					endPresentation();
				}
			}
            break;
        default:
            break;
    }
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<commit_msg>Changed mouse button config to work with custom foot pedal.<commit_after>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
	// Global settings.
	ofSetWindowTitle("Presenter");
	ofSetVerticalSync(true);
	ofEnableSmoothing();
	ofSetFrameRate(60);

	// Position the window in the centre of the screen.
	ofSetWindowPosition((ofGetScreenWidth() - ofGetWindowWidth()) / 2, (ofGetScreenHeight() - ofGetWindowHeight()) / 2);

	// Set status to Welcome screen.
	status = PRESENTER_STATUS_WELCOME;

	// Load logo for welcome screen.
	logo.loadImage("logo.png");
	if(logo.getWidth()>550){
		logo.resize(550, logo.getHeight() / logo.getWidth() * 550);
	}

	// Create presentation chooser buttons.
	gui = new ofxUICanvas();
	gui->setPosition(650, 250);
	gui->setDrawBack(false);

	// Setup custom theme for GUI.
	ofxUIColor cb = ofxUIColor(38, 147, 255, 200);
    ofxUIColor co = ofxUIColor(38, 147, 255, 255);
    ofxUIColor coh = OFX_UI_COLOR_OUTLINE_HIGHLIGHT;
    ofxUIColor cf = ofxUIColor(255, 255, 255, 255);
    ofxUIColor cfh = OFX_UI_COLOR_FILL_HIGHLIGHT;
    ofxUIColor cp = ofxUIColor(38, 147, 255, 255);
    ofxUIColor cpo = OFX_UI_COLOR_PADDED_OUTLINE;
    gui->setUIColors( cb, co, coh, cf, cfh, cp, cpo );

	gui->addLabel("Select a presentation:", OFX_UI_FONT_MEDIUM)->setColorFill(ofxUIColor(0, 0, 0, 255));
    gui->addSpacer();

	// Each directory in bin/data/Presentations is concidered a presentation.
	int i, size;
	ofDirectory presentations;
	presentations = ofDirectory("Presentations");
	presentations.sort();
	presentations.listDir();
	size = presentations.size();

	for (i = 0; i < size; i++){
		if (presentations.getFile(i).isDirectory()==1){
			gui->addLabelButton(presentations.getFile(i).getFileName(), false, 300, 30, 0, 0, true);
		}
	}

    gui->autoSizeToFitWidgets();
    ofAddListener(gui->newGUIEvent,this,&ofApp::guiEvent);

	// Create shutdown button.
	shutdown = new ofxUICanvas();
	shutdown->setPosition(ofGetWindowWidth()-60, 10);
	shutdown->setDrawBack(false);

	shutdown->setGlobalButtonDimension(44);
	shutdown->addImageButton("Shutdown", "shutdown.png", false);
	shutdown->autoSizeToFitWidgets();
    ofAddListener(shutdown->newGUIEvent,this,&ofApp::guiEvent);

}

//--------------------------------------------------------------
void ofApp::update(){
	if(status == PRESENTER_STATUS_WELCOME){

	} else if (status == PRESENTER_STATUS_PRESENTATION){
		if(presentation != NULL){
			presentation->update();
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
	if(status == PRESENTER_STATUS_WELCOME){
		ofBackground(ofColor::white);
		logo.draw(50,75);
	} else if (status == PRESENTER_STATUS_PRESENTATION){
		if(presentation != NULL){
			presentation->draw();
		}
	}
}

void ofApp::guiEvent(ofxUIEventArgs &e)
{
	string name = e.widget->getName();
	int kind = e.widget->getKind();

    if(kind == OFX_UI_WIDGET_LABELBUTTON)
    {
        ofxUIButton *button = (ofxUIButton *) e.widget;
		if(!button->getValue()){
			// load presentation xml file.
			presentation = new Presentation(name);

			// set the status and hide the gui on welcome screen.
			status = PRESENTER_STATUS_PRESENTATION;
			ofHideCursor();
			gui->setVisible(false);
			shutdown->setVisible(false);

			cout << name << "\t value: " << button->getValue() << endl;
		}
    }
    else if(kind == OFX_UI_WIDGET_IMAGEBUTTON)
    {
        ofxUIImageButton *button = (ofxUIImageButton *) e.widget;
        if(button->getValue()){

#if defined(TARGET_RASPBERRY_PI)
			// On Raspberry Pi, shutdown.
			std::system("sudo shutdown -h now");
#else
			// Desktop applications, close the application.
			std::exit(0);
#endif

		}
    }
}

//--------------------------------------------------------------
void ofApp::exit()
{
    delete gui;
}

void ofApp::endPresentation(){
	status = PRESENTER_STATUS_WELCOME;
	ofShowCursor();
	gui->setVisible(true);
	shutdown->setVisible(true);
	delete presentation;
	presentation = NULL;
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key)
{
    switch (key)
    {
        case 'g':
            gui->toggleVisible();
			break;
		case OF_KEY_RIGHT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->next()==0){
					endPresentation();
				}
			}
            break;
		case OF_KEY_LEFT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->previous()==0){
					endPresentation();
				}
			}
            break;
        default:
            break;
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
	switch (button)
    {
		case OF_MOUSE_BUTTON_RIGHT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->next()==0){
					endPresentation();
				}
			}
            break;
		case OF_MOUSE_BUTTON_LEFT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->previous()==0){
					endPresentation();
				}
			}
            break;
        default:
            break;
    }
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>


<commit_before>#ifndef COFFEE_MILL_PDB_SEQ
#define COFFEE_MILL_PDB_SEQ
#include <mill/data/PDBChain.hpp>
#include <mill/util/string.hpp>
#include <string>
#include <map>

namespace mill
{

template<typename Iterator>
struct residue_name_iterator
{
    residue_name_iterator(Iterator iter) : iter_(iter){}

    std::string operator*() const
    {
        return remove_all(' ', iter_->residue_name());
    }

    residue_name_iterator& operator++()
    {
        ++iter_;
        return *this;
    }
    residue_name_iterator& operator++(int)
    {
        const auto tmp = *this;
        ++(*this);
        return tmp;
    }

    Iterator iter_;
};

template<typename Iterator>
inline residue_name_iterator<Iterator>
wrap_residue_name(Iterator iter)
{
    return residue_name_iterator<Iterator>(iter);
}

template<typename Iterator>
inline bool operator==(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return lhs.iter_ == rhs.iter_;
}

template<typename Iterator>
inline bool operator<(residue_name_iterator<Iterator> const& lhs,
                      residue_name_iterator<Iterator> const& rhs)
{
    return lhs.iter_ < rhs.iter_;
}

template<typename Iterator>
inline bool operator!=(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return !(lhs == rhs);
}

template<typename Iterator>
inline bool operator<=(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return (lhs < rhs) || (lhs == rhs);
}

template<typename Iterator>
inline bool operator>(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return !(lhs <= rhs);
}

template<typename Iterator>
inline bool operator>=(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return !(lhs < rhs);
}

struct amino_acid_code
{
    char operator()(std::string const& s) const {return codes.at(s);}
    std::string const& operator()(char s) const
    {
        return std::find_if(codes.cbegin(), codes.cend(),
            [=](const std::pair<std::string, char>& p){return p.second==s;}
            )->first;
    }

    std::map<std::string, char> codes = {
        {"ALA", 'A'},
        {"ASX", 'B'},
        {"CYS", 'C'},
        {"ASP", 'D'},
        {"GLU", 'E'},
        {"PHE", 'F'},
        {"GLY", 'G'},
        {"HIS", 'H'},
        {"ILE", 'I'},
        {"LYS", 'K'},
        {"LEU", 'L'},
        {"MET", 'M'},
        {"ASN", 'N'},
        {"PRO", 'P'},
        {"GLN", 'Q'},
        {"ARG", 'R'},
        {"SER", 'S'},
        {"THR", 'T'},
        {"SEC", 'U'},
        {"VAL", 'V'},
        {"TRP", 'W'},
        {"XAA", 'X'},
        {"TYR", 'Y'},
        {"GLX", 'Z'}
    };
};

struct generate_sequence
{
    char operator()(const std::string& res) const
    {
        if(res.size() == 1)
        {
            return res.front();
        }
        else if(res[0] == 'D' && res.size() == 2)
        {
            return res[1];
        }
        else if(res.size() == 3)
        {
            return amino(res);
        }
        else
            throw std::invalid_argument("unknown sequence: " + res);
    }

    amino_acid_code amino;
};

// argv := {"seq", "file.pdb"}
template<typename vectorT>
int mill_pdb_seq(int argument_c, char **argument_v)
{
    if(argument_c < 2)
    {
        std::cerr << "error: mill pdb seq: too few commands" << std::endl;
        return 1;
    }

    const std::string pdbname(argument_v[1]);
    PDBReader<vectorT> reader;
    const auto chains = reader.parse(reader.read(pdbname));

    for(auto&& chain : chains)
    {
        std::string sequence(chain.size(), ' ');
        std::transform(wrap_residue_name(chain.cbegin()),
                       wrap_residue_name(chain.cend()),
                       sequence.begin(),
                       generate_sequence());
        std::cout << "chain " << chain.chain_id() << ": " << sequence << std::endl;
    }
    return 0;
}

} // mill
#endif /* COFFEE_MILL_PDB_SEQ */
<commit_msg>use amino_acid_code<commit_after>#ifndef COFFEE_MILL_PDB_SEQ
#define COFFEE_MILL_PDB_SEQ
#include <mill/data/PDBChain.hpp>
#include <mill/util/string.hpp>
#include <mill/util/amino_acid_code.hpp>

namespace mill
{

template<typename Iterator>
struct residue_name_iterator
{
    residue_name_iterator(Iterator iter) : iter_(iter){}

    std::string operator*() const
    {
        return remove_all(' ', iter_->residue_name());
    }

    residue_name_iterator& operator++()
    {
        ++iter_;
        return *this;
    }
    residue_name_iterator& operator++(int)
    {
        const auto tmp = *this;
        ++(*this);
        return tmp;
    }

    Iterator iter_;
};

template<typename Iterator>
inline residue_name_iterator<Iterator>
wrap_residue_name(Iterator iter)
{
    return residue_name_iterator<Iterator>(iter);
}

template<typename Iterator>
inline bool operator==(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return lhs.iter_ == rhs.iter_;
}

template<typename Iterator>
inline bool operator<(residue_name_iterator<Iterator> const& lhs,
                      residue_name_iterator<Iterator> const& rhs)
{
    return lhs.iter_ < rhs.iter_;
}

template<typename Iterator>
inline bool operator!=(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return !(lhs == rhs);
}

template<typename Iterator>
inline bool operator<=(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return (lhs < rhs) || (lhs == rhs);
}

template<typename Iterator>
inline bool operator>(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return !(lhs <= rhs);
}

template<typename Iterator>
inline bool operator>=(residue_name_iterator<Iterator> const& lhs,
                       residue_name_iterator<Iterator> const& rhs)
{
    return !(lhs < rhs);
}

struct generate_sequence
{
    char operator()(const std::string& res) const
    {
        if(res.size() == 1)
        {
            return res.front();
        }
        else if(res[0] == 'D' && res.size() == 2)
        {
            return res[1];
        }
        else if(res.size() == 3)
        {
            return amino(res);
        }
        else
            throw std::invalid_argument("unknown sequence: " + res);
    }

    amino_acid_code amino;
};

// argv := {"seq", "file.pdb"}
template<typename vectorT>
int mill_pdb_seq(int argument_c, char **argument_v)
{
    if(argument_c < 2)
    {
        std::cerr << "error: mill pdb seq: too few commands" << std::endl;
        return 1;
    }

    const std::string pdbname(argument_v[1]);
    PDBReader<vectorT> reader;
    const auto chains = reader.parse(reader.read(pdbname));

    for(auto&& chain : chains)
    {
        std::string sequence(chain.size(), ' ');
        std::transform(wrap_residue_name(chain.cbegin()),
                       wrap_residue_name(chain.cend()),
                       sequence.begin(),
                       generate_sequence());
        std::cout << "chain " << chain.chain_id() << ": " << sequence << std::endl;
    }
    return 0;
}

} // mill
#endif /* COFFEE_MILL_PDB_SEQ */
<|endoftext|>


<commit_before>/* value.tcc                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 25 Mar 2014
   FreeBSD-style copyright and disclaimer apply

   Template implementation for Value.
*/

#pragma once

#include "value.h"
#include "reflection.h"

namespace reflect {

/******************************************************************************/
/* VALUE                                                                      */
/******************************************************************************/

template<typename T>
Value::
Value(T&& value) :
    value_(&value), reflection_(reflect<T>())
{
    if (refType(std::forward<T>(value)) == RefType::RValue)
        storage.reset(value_ = new T(std::move(value)));
}

template<typename T>
T
Value::
cast()
{
    assert(!isVoid());

    typedef typename std::decay<T>::type CleanT;
    assert(reflection_->isConvertibleTo<CleanT>());

    return cast<T>(reinterpret_cast<CleanT*>(value),
            std::is_lvalue_reference<T>());
}

/** Return by lvalue-ref or copy. */
template<typename T, typename U>
T
Value::
cast(U* value, std::false_type)
{
    return *value;
}

/** Return by rvalue-ref so gut our object in the process. */
template<typename T, typename U>
T
Value::
cast(U* value, std::true_type)
{
    assert(refType() == RefType::RValue);
    assert(storage.unique());

    auto toReturn = std::move(*value);
    *this = Value();

    return std::move(toReturn);
}

} // reflect
<commit_msg>Fixed the value.tcc includes.<commit_after>/* value.tcc                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 25 Mar 2014
   FreeBSD-style copyright and disclaimer apply

   Template implementation for Value.
*/

#include "reflect.h"
#pragma once

namespace reflect {

/******************************************************************************/
/* VALUE                                                                      */
/******************************************************************************/

template<typename T>
Value::
Value(T&& value) :
    value_(&value), reflection_(reflect<T>())
{
    if (refType(std::forward<T>(value)) == RefType::RValue)
        storage.reset(value_ = new T(std::move(value)));
}

template<typename T>
T
Value::
cast()
{
    assert(!isVoid());

    typedef typename std::decay<T>::type CleanT;
    assert(reflection_->isConvertibleTo<CleanT>());

    return cast<T>(reinterpret_cast<CleanT*>(value),
            std::is_lvalue_reference<T>());
}

/** Return by lvalue-ref or copy. */
template<typename T, typename U>
T
Value::
cast(U* value, std::false_type)
{
    return *value;
}

/** Return by rvalue-ref so gut our object in the process. */
template<typename T, typename U>
T
Value::
cast(U* value, std::true_type)
{
    assert(refType() == RefType::RValue);
    assert(storage.unique());

    auto toReturn = std::move(*value);
    *this = Value();

    return std::move(toReturn);
}

} // reflect
<|endoftext|>


<commit_before>// Copyright (c) 2005-2022 Jay Berkenbilt
//
// This file is part of qpdf.
//
// 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.
//
// Versions of qpdf prior to version 7 were released under the terms
// of version 2.0 of the Artistic License. At your option, you may
// continue to consider qpdf to be licensed under those terms. Please
// see the manual for additional information.

// This class implements a simple writer for saving QPDF objects to
// new PDF files.  See comments through the header file for additional
// details.

#ifndef PDFVERSION_HH
#define PDFVERSION_HH

#include <qpdf/DLL.h>
#include <string>

class PDFVersion
{
  public:
    // Represent a PDF version. PDF versions are typically
    // major.minor, but PDF 1.7 has several extension levels as the
    // ISO 32000 spec was in progress. This class helps with
    // comparison of versions.
    QPDF_DLL
    PDFVersion();
    QPDF_DLL
    PDFVersion(PDFVersion const&) = default;
    QPDF_DLL
    PDFVersion(int major, int minor, int extension = 0);
    QPDF_DLL
    bool operator<(PDFVersion const& rhs) const;
    QPDF_DLL
    bool operator==(PDFVersion const& rhs) const;

    // Replace this version with the other one if the other one is
    // greater.
    QPDF_DLL
    void updateIfGreater(PDFVersion const& other);

    // Initialize a string and integer suitable for passing to
    // QPDFWriter::setMinimumPDFVersion or QPDFWriter::forcePDFVersion.
    QPDF_DLL
    void getVersion(std::string& version, int& extension_level) const;

    QPDF_DLL
    int getMajor() const;
    QPDF_DLL
    int getMinor() const;
    QPDF_DLL
    int getExtensionLevel() const;

  private:
    int major_version;
    int minor_version;
    int extension_level;
};

#endif // PDFVERSION_HH
<commit_msg>Fix lgtm warning<commit_after>// Copyright (c) 2005-2022 Jay Berkenbilt
//
// This file is part of qpdf.
//
// 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.
//
// Versions of qpdf prior to version 7 were released under the terms
// of version 2.0 of the Artistic License. At your option, you may
// continue to consider qpdf to be licensed under those terms. Please
// see the manual for additional information.

// This class implements a simple writer for saving QPDF objects to
// new PDF files.  See comments through the header file for additional
// details.

#ifndef PDFVERSION_HH
#define PDFVERSION_HH

#include <qpdf/DLL.h>
#include <string>

class PDFVersion
{
  public:
    // Represent a PDF version. PDF versions are typically
    // major.minor, but PDF 1.7 has several extension levels as the
    // ISO 32000 spec was in progress. This class helps with
    // comparison of versions.
    QPDF_DLL
    PDFVersion();
    QPDF_DLL
    PDFVersion(PDFVersion const&) = default;
    QPDF_DLL
    PDFVersion& operator=(PDFVersion const&) = default;
    QPDF_DLL
    PDFVersion(int major, int minor, int extension = 0);
    QPDF_DLL
    bool operator<(PDFVersion const& rhs) const;
    QPDF_DLL
    bool operator==(PDFVersion const& rhs) const;

    // Replace this version with the other one if the other one is
    // greater.
    QPDF_DLL
    void updateIfGreater(PDFVersion const& other);

    // Initialize a string and integer suitable for passing to
    // QPDFWriter::setMinimumPDFVersion or QPDFWriter::forcePDFVersion.
    QPDF_DLL
    void getVersion(std::string& version, int& extension_level) const;

    QPDF_DLL
    int getMajor() const;
    QPDF_DLL
    int getMinor() const;
    QPDF_DLL
    int getExtensionLevel() const;

  private:
    int major_version;
    int minor_version;
    int extension_level;
};

#endif // PDFVERSION_HH
<|endoftext|>


<commit_before>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_MATH_QUATERNION_HPP
#define OUZEL_MATH_QUATERNION_HPP

#include <array>
#include <cmath>
#include <cstddef>
#include <limits>
#include "Vector.hpp"

namespace ouzel
{
    template <typename T> class Quaternion final
    {
    public:
#if defined(__SSE__)
        alignas(4 * sizeof(T))
#endif
        std::array<T, 4> v{};

        constexpr Quaternion() noexcept {}

        constexpr Quaternion(const T x, const T y, const T z, const T w) noexcept:
            v{x, y, z, w}
        {
        }

        auto& operator[](std::size_t index) noexcept { return v[index]; }
        constexpr auto operator[](std::size_t index) const noexcept { return v[index]; }

        auto& x() noexcept { return v[0]; }
        constexpr auto x() const noexcept { return v[0]; }

        auto& y() noexcept { return v[1]; }
        constexpr auto y() const noexcept { return v[1]; }

        auto& z() noexcept { return v[2]; }
        constexpr auto z() const noexcept { return v[2]; }

        auto& w() noexcept { return v[3]; }
        constexpr auto w() const noexcept { return v[3]; }

        static constexpr Quaternion identity() noexcept
        {
            return Quaternion{0, 0, 0, 1};
        }

        constexpr const Quaternion operator*(const Quaternion& q) const noexcept
        {
            return Quaternion{
                v[0] * q.v[3] + v[1] * q.v[2] - v[2] * q.v[1] + v[3] * q.v[0],
                -v[0] * q.v[2] + v[1] * q.v[3] + v[2] * q.v[0] + v[3] * q.v[1],
                v[0] * q.v[1] - v[1] * q.v[0] + v[2] * q.v[3] + v[3] * q.v[2],
                -v[0] * q.v[0] - v[1] * q.v[1] - v[2] * q.v[2] + v[3] * q.v[3]
            };
        }

        constexpr Quaternion& operator*=(const Quaternion& q) noexcept
        {
            constexpr T tempX = v[0] * q.v[3] + v[1] * q.v[2] - v[2] * q.v[1] + v[3] * q.v[0];
            constexpr T tempY = -v[0] * q.v[2] + v[1] * q.v[3] + v[2] * q.v[0] + v[3] * q.v[1];
            constexpr T tempZ = v[0] * q.v[1] - v[1] * q.v[0] + v[2] * q.v[3] + v[3] * q.v[2];
            constexpr T tempW = -v[0] * q.v[0] - v[1] * q.v[1] - v[2] * q.v[2] + v[3] * q.v[3];

            v[0] = tempX;
            v[1] = tempY;
            v[2] = tempZ;
            v[3] = tempW;

            return *this;
        }

        constexpr const Quaternion operator*(const T scalar) const noexcept
        {
            return Quaternion(v[0] * scalar,
                              v[1] * scalar,
                              v[2] * scalar,
                              v[3] * scalar);
        }

        constexpr Quaternion& operator*=(const T scalar) noexcept
        {
            v[0] *= scalar;
            v[1] *= scalar;
            v[2] *= scalar;
            v[3] *= scalar;

            return *this;
        }

        constexpr const Quaternion operator/(const T scalar) const noexcept
        {
            return Quaternion(v[0] / scalar,
                              v[1] / scalar,
                              v[2] / scalar,
                              v[3] / scalar);
        }

        constexpr Quaternion& operator/=(const T scalar) noexcept
        {
            v[0] /= scalar;
            v[1] /= scalar;
            v[2] /= scalar;
            v[3] /= scalar;

            return *this;
        }

        constexpr const Quaternion operator-() const noexcept
        {
            return Quaternion(-v[0], -v[1], -v[2], -v[3]);
        }

        constexpr const Quaternion operator+(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] + q.v[0],
                              v[1] + q.v[1],
                              v[2] + q.v[2],
                              v[3] + q.v[3]);
        }

        constexpr Quaternion& operator+=(const Quaternion& q) noexcept
        {
            v[0] += q.v[0];
            v[1] += q.v[1];
            v[2] += q.v[2];
            v[3] += q.v[3];

            return *this;
        }

        constexpr const Quaternion operator-(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] - q.v[0],
                              v[1] - q.v[1],
                              v[2] - q.v[2],
                              v[3] - q.v[3]);
        }

        constexpr Quaternion& operator-=(const Quaternion& q) noexcept
        {
            v[0] -= q.v[0];
            v[1] -= q.v[1];
            v[2] -= q.v[2];
            v[3] -= q.v[3];

            return *this;
        }

        constexpr bool operator==(const Quaternion& q) const noexcept
        {
            return v[0] == q.v[0] && v[1] == q.v[1] && v[2] == q.v[2] && v[3] == q.v[3];
        }

        constexpr bool operator!=(const Quaternion& q) const noexcept
        {
            return v[0] != q.v[0] || v[1] != q.v[1] || v[2] != q.v[2] || v[3] != q.v[3];
        }

        constexpr void negate() noexcept
        {
            v[0] = -v[0];
            v[1] = -v[1];
            v[2] = -v[2];
            v[3] = -v[3];
        }

        constexpr void conjugate() noexcept
        {
            v[0] = -v[0];
            v[1] = -v[1];
            v[2] = -v[2];
        }

        constexpr void invert() noexcept
        {
            constexpr T squared = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; // norm squared
            if (squared <= std::numeric_limits<T>::min())
                return;

            // conjugate divided by norm squared
            const T multiplier = T(1) / squared;
            v[0] = -v[0] * multiplier;
            v[1] = -v[1] * multiplier;
            v[2] = -v[2] * multiplier;
            v[3] = v[3] * multiplier;
        }

        auto getNorm() const noexcept
        {
            constexpr T n = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (n == T(1)) // already normalized
                return T(1);

            return std::sqrt(n);
        }

        void normalize() noexcept
        {
            constexpr T squared = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (squared == T(1)) // already normalized
                return;

            const T length = std::sqrt(squared);
            if (length <= std::numeric_limits<T>::min()) // too close to zero
                return;

            const T multiplier = T(1) / length;
            v[0] *= multiplier;
            v[1] *= multiplier;
            v[2] *= multiplier;
            v[3] *= multiplier;
        }

        Quaternion normalized() const noexcept
        {
            constexpr T squared = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (squared == T(1)) // already normalized
                return *this;

            const T length = std::sqrt(squared);
            if (length <= std::numeric_limits<T>::min()) // too close to zero
                return *this;

            const T multiplier = T(1) / length;
            return Quaternion(v[0] * multiplier,
                              v[1] * multiplier,
                              v[2] * multiplier,
                              v[3] * multiplier);
        }

        void rotate(const T angle, const Vector<T, 3>& axis) noexcept
        {
            const auto normalizedAxis = axis.normalized();

            const T cosAngle = std::cos(angle / T(2));
            const T sinAngle = std::sin(angle / T(2));

            v[0] = normalizedAxis.v[0] * sinAngle;
            v[1] = normalizedAxis.v[1] * sinAngle;
            v[2] = normalizedAxis.v[2] * sinAngle;
            v[3] = cosAngle;
        }

        void getRotation(T& angle, Vector<T, 3>& axis) const noexcept
        {
            angle = T(2) * std::acos(v[3]);
            const T s = std::sqrt(T(1) - v[3] * v[3]);
            if (s <= std::numeric_limits<T>::min()) // too close to zero
            {
                axis.v[0] = v[0];
                axis.v[1] = v[1];
                axis.v[2] = v[2];
            }
            else
            {
                axis.v[0] = v[0] / s;
                axis.v[1] = v[1] / s;
                axis.v[2] = v[2] / s;
            }
        }

        Vector<T, 3> getEulerAngles() const noexcept
        {
            return Vector<T, 3>{
                std::atan2(2 * (v[1] * v[2] + v[3] * v[0]), v[3] * v[3] - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]),
                std::asin(-2 * (v[0] * v[2] - v[3] * v[1])),
                std::atan2(2 * (v[0] * v[1] + v[3] * v[2]), v[3] * v[3] + v[0] * v[0] - v[1] * v[1] - v[2] * v[2])
            };
        }

        auto getEulerAngleX() const noexcept
        {
            return std::atan2(T(2) * (v[1] * v[2] + v[3] * v[0]), v[3] * v[3] - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]);
        }

        auto getEulerAngleY() const noexcept
        {
            return std::asin(T(-2) * (v[0] * v[2] - v[3] * v[1]));
        }

        auto getEulerAngleZ() const noexcept
        {
            return std::atan2(T(2) * (v[0] * v[1] + v[3] * v[2]), v[3] * v[3] + v[0] * v[0] - v[1] * v[1] - v[2] * v[2]);
        }

        void setEulerAngles(const Vector<T, 3>& angles) noexcept
        {
            const T angleR = angles.v[0] / T(2);
            const T sr = std::sin(angleR);
            const T cr = std::cos(angleR);

            const T angleP = angles.v[1] / T(2);
            const T sp = std::sin(angleP);
            const T cp = std::cos(angleP);

            const T angleY = angles.v[2] / T(2);
            const T sy = std::sin(angleY);
            const T cy = std::cos(angleY);

            const T cpcy = cp * cy;
            const T spcy = sp * cy;
            const T cpsy = cp * sy;
            const T spsy = sp * sy;

            v[0] = sr * cpcy - cr * spsy;
            v[1] = cr * spcy + sr * cpsy;
            v[2] = cr * cpsy - sr * spcy;
            v[3] = cr * cpcy + sr * spsy;
        }

        const Vector<T, 3> operator*(const Vector<T, 3>& vector) const noexcept
        {
            return rotateVector(vector);
        }

        Vector<T, 3> rotateVector(const Vector<T, 3>& vector) const noexcept
        {
            constexpr Vector<T, 3> q(v[0], v[1], v[2]);
            const Vector<T, 3> t = T(2) * q.cross(vector);
            return vector + (v[3] * t) + q.cross(t);
        }

        Vector<T, 3> getRightVector() const noexcept
        {
            return rotateVector(Vector<T, 3>(1, 0, 0));
        }

        Vector<T, 3> getUpVector() const noexcept
        {
            return rotateVector(Vector<T, 3>(0, 1, 0));
        }

        Vector<T, 3> getForwardVector() const noexcept
        {
            return rotateVector(Vector<T, 3>(0, 0, 1));
        }

        constexpr Quaternion& lerp(const Quaternion& q1, const Quaternion& q2, T t) noexcept
        {
            *this = (q1 * (T(1) - t)) + (q2 * t);
            return *this;
        }
    };

    using QuaternionF = Quaternion<float>;
}

#endif // OUZEL_MATH_QUATERNION_HPP
<commit_msg>Declare temp const instead of constexpr for cases when this is not constexpr<commit_after>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_MATH_QUATERNION_HPP
#define OUZEL_MATH_QUATERNION_HPP

#include <array>
#include <cmath>
#include <cstddef>
#include <limits>
#include "Vector.hpp"

namespace ouzel
{
    template <typename T> class Quaternion final
    {
    public:
#if defined(__SSE__)
        alignas(4 * sizeof(T))
#endif
        std::array<T, 4> v{};

        constexpr Quaternion() noexcept {}

        constexpr Quaternion(const T x, const T y, const T z, const T w) noexcept:
            v{x, y, z, w}
        {
        }

        auto& operator[](std::size_t index) noexcept { return v[index]; }
        constexpr auto operator[](std::size_t index) const noexcept { return v[index]; }

        auto& x() noexcept { return v[0]; }
        constexpr auto x() const noexcept { return v[0]; }

        auto& y() noexcept { return v[1]; }
        constexpr auto y() const noexcept { return v[1]; }

        auto& z() noexcept { return v[2]; }
        constexpr auto z() const noexcept { return v[2]; }

        auto& w() noexcept { return v[3]; }
        constexpr auto w() const noexcept { return v[3]; }

        static constexpr Quaternion identity() noexcept
        {
            return Quaternion{0, 0, 0, 1};
        }

        constexpr const Quaternion operator*(const Quaternion& q) const noexcept
        {
            return Quaternion{
                v[0] * q.v[3] + v[1] * q.v[2] - v[2] * q.v[1] + v[3] * q.v[0],
                -v[0] * q.v[2] + v[1] * q.v[3] + v[2] * q.v[0] + v[3] * q.v[1],
                v[0] * q.v[1] - v[1] * q.v[0] + v[2] * q.v[3] + v[3] * q.v[2],
                -v[0] * q.v[0] - v[1] * q.v[1] - v[2] * q.v[2] + v[3] * q.v[3]
            };
        }

        constexpr Quaternion& operator*=(const Quaternion& q) noexcept
        {
            const auto tempX = v[0] * q.v[3] + v[1] * q.v[2] - v[2] * q.v[1] + v[3] * q.v[0];
            const auto tempY = -v[0] * q.v[2] + v[1] * q.v[3] + v[2] * q.v[0] + v[3] * q.v[1];
            const auto tempZ = v[0] * q.v[1] - v[1] * q.v[0] + v[2] * q.v[3] + v[3] * q.v[2];
            const auto tempW = -v[0] * q.v[0] - v[1] * q.v[1] - v[2] * q.v[2] + v[3] * q.v[3];

            v[0] = tempX;
            v[1] = tempY;
            v[2] = tempZ;
            v[3] = tempW;

            return *this;
        }

        constexpr const Quaternion operator*(const T scalar) const noexcept
        {
            return Quaternion(v[0] * scalar,
                              v[1] * scalar,
                              v[2] * scalar,
                              v[3] * scalar);
        }

        constexpr Quaternion& operator*=(const T scalar) noexcept
        {
            v[0] *= scalar;
            v[1] *= scalar;
            v[2] *= scalar;
            v[3] *= scalar;

            return *this;
        }

        constexpr const Quaternion operator/(const T scalar) const noexcept
        {
            return Quaternion(v[0] / scalar,
                              v[1] / scalar,
                              v[2] / scalar,
                              v[3] / scalar);
        }

        constexpr Quaternion& operator/=(const T scalar) noexcept
        {
            v[0] /= scalar;
            v[1] /= scalar;
            v[2] /= scalar;
            v[3] /= scalar;

            return *this;
        }

        constexpr const Quaternion operator-() const noexcept
        {
            return Quaternion(-v[0], -v[1], -v[2], -v[3]);
        }

        constexpr const Quaternion operator+(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] + q.v[0],
                              v[1] + q.v[1],
                              v[2] + q.v[2],
                              v[3] + q.v[3]);
        }

        constexpr Quaternion& operator+=(const Quaternion& q) noexcept
        {
            v[0] += q.v[0];
            v[1] += q.v[1];
            v[2] += q.v[2];
            v[3] += q.v[3];

            return *this;
        }

        constexpr const Quaternion operator-(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] - q.v[0],
                              v[1] - q.v[1],
                              v[2] - q.v[2],
                              v[3] - q.v[3]);
        }

        constexpr Quaternion& operator-=(const Quaternion& q) noexcept
        {
            v[0] -= q.v[0];
            v[1] -= q.v[1];
            v[2] -= q.v[2];
            v[3] -= q.v[3];

            return *this;
        }

        constexpr bool operator==(const Quaternion& q) const noexcept
        {
            return v[0] == q.v[0] && v[1] == q.v[1] && v[2] == q.v[2] && v[3] == q.v[3];
        }

        constexpr bool operator!=(const Quaternion& q) const noexcept
        {
            return v[0] != q.v[0] || v[1] != q.v[1] || v[2] != q.v[2] || v[3] != q.v[3];
        }

        constexpr void negate() noexcept
        {
            v[0] = -v[0];
            v[1] = -v[1];
            v[2] = -v[2];
            v[3] = -v[3];
        }

        constexpr void conjugate() noexcept
        {
            v[0] = -v[0];
            v[1] = -v[1];
            v[2] = -v[2];
        }

        constexpr void invert() noexcept
        {
            constexpr T squared = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; // norm squared
            if (squared <= std::numeric_limits<T>::min())
                return;

            // conjugate divided by norm squared
            const T multiplier = T(1) / squared;
            v[0] = -v[0] * multiplier;
            v[1] = -v[1] * multiplier;
            v[2] = -v[2] * multiplier;
            v[3] = v[3] * multiplier;
        }

        auto getNorm() const noexcept
        {
            constexpr T n = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (n == T(1)) // already normalized
                return T(1);

            return std::sqrt(n);
        }

        void normalize() noexcept
        {
            constexpr T squared = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (squared == T(1)) // already normalized
                return;

            const T length = std::sqrt(squared);
            if (length <= std::numeric_limits<T>::min()) // too close to zero
                return;

            const T multiplier = T(1) / length;
            v[0] *= multiplier;
            v[1] *= multiplier;
            v[2] *= multiplier;
            v[3] *= multiplier;
        }

        Quaternion normalized() const noexcept
        {
            constexpr T squared = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (squared == T(1)) // already normalized
                return *this;

            const T length = std::sqrt(squared);
            if (length <= std::numeric_limits<T>::min()) // too close to zero
                return *this;

            const T multiplier = T(1) / length;
            return Quaternion(v[0] * multiplier,
                              v[1] * multiplier,
                              v[2] * multiplier,
                              v[3] * multiplier);
        }

        void rotate(const T angle, const Vector<T, 3>& axis) noexcept
        {
            const auto normalizedAxis = axis.normalized();

            const T cosAngle = std::cos(angle / T(2));
            const T sinAngle = std::sin(angle / T(2));

            v[0] = normalizedAxis.v[0] * sinAngle;
            v[1] = normalizedAxis.v[1] * sinAngle;
            v[2] = normalizedAxis.v[2] * sinAngle;
            v[3] = cosAngle;
        }

        void getRotation(T& angle, Vector<T, 3>& axis) const noexcept
        {
            angle = T(2) * std::acos(v[3]);
            const T s = std::sqrt(T(1) - v[3] * v[3]);
            if (s <= std::numeric_limits<T>::min()) // too close to zero
            {
                axis.v[0] = v[0];
                axis.v[1] = v[1];
                axis.v[2] = v[2];
            }
            else
            {
                axis.v[0] = v[0] / s;
                axis.v[1] = v[1] / s;
                axis.v[2] = v[2] / s;
            }
        }

        Vector<T, 3> getEulerAngles() const noexcept
        {
            return Vector<T, 3>{
                std::atan2(2 * (v[1] * v[2] + v[3] * v[0]), v[3] * v[3] - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]),
                std::asin(-2 * (v[0] * v[2] - v[3] * v[1])),
                std::atan2(2 * (v[0] * v[1] + v[3] * v[2]), v[3] * v[3] + v[0] * v[0] - v[1] * v[1] - v[2] * v[2])
            };
        }

        auto getEulerAngleX() const noexcept
        {
            return std::atan2(T(2) * (v[1] * v[2] + v[3] * v[0]), v[3] * v[3] - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]);
        }

        auto getEulerAngleY() const noexcept
        {
            return std::asin(T(-2) * (v[0] * v[2] - v[3] * v[1]));
        }

        auto getEulerAngleZ() const noexcept
        {
            return std::atan2(T(2) * (v[0] * v[1] + v[3] * v[2]), v[3] * v[3] + v[0] * v[0] - v[1] * v[1] - v[2] * v[2]);
        }

        void setEulerAngles(const Vector<T, 3>& angles) noexcept
        {
            const T angleR = angles.v[0] / T(2);
            const T sr = std::sin(angleR);
            const T cr = std::cos(angleR);

            const T angleP = angles.v[1] / T(2);
            const T sp = std::sin(angleP);
            const T cp = std::cos(angleP);

            const T angleY = angles.v[2] / T(2);
            const T sy = std::sin(angleY);
            const T cy = std::cos(angleY);

            const T cpcy = cp * cy;
            const T spcy = sp * cy;
            const T cpsy = cp * sy;
            const T spsy = sp * sy;

            v[0] = sr * cpcy - cr * spsy;
            v[1] = cr * spcy + sr * cpsy;
            v[2] = cr * cpsy - sr * spcy;
            v[3] = cr * cpcy + sr * spsy;
        }

        const Vector<T, 3> operator*(const Vector<T, 3>& vector) const noexcept
        {
            return rotateVector(vector);
        }

        Vector<T, 3> rotateVector(const Vector<T, 3>& vector) const noexcept
        {
            constexpr Vector<T, 3> q(v[0], v[1], v[2]);
            const Vector<T, 3> t = T(2) * q.cross(vector);
            return vector + (v[3] * t) + q.cross(t);
        }

        Vector<T, 3> getRightVector() const noexcept
        {
            return rotateVector(Vector<T, 3>(1, 0, 0));
        }

        Vector<T, 3> getUpVector() const noexcept
        {
            return rotateVector(Vector<T, 3>(0, 1, 0));
        }

        Vector<T, 3> getForwardVector() const noexcept
        {
            return rotateVector(Vector<T, 3>(0, 0, 1));
        }

        constexpr Quaternion& lerp(const Quaternion& q1, const Quaternion& q2, T t) noexcept
        {
            *this = (q1 * (T(1) - t)) + (q2 * t);
            return *this;
        }
    };

    using QuaternionF = Quaternion<float>;
}

#endif // OUZEL_MATH_QUATERNION_HPP
<|endoftext|>