<commit_before>#pragma once

#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <sys/time.h>
#include <stdarg.h>

#include <zcm/zcm-cpp.hpp>
#include <zcm/util/circular.hpp>

namespace TimeUtil {

static uint64_t utime()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
}

}

// *****************************************************************************
// Insanely hacky trick to determine at compile time if a zcmtype has a
// field called "utime"
template <typename F> struct hasUtime {
    struct Fallback { void* utime; }; // introduce member name "utime"
    struct Derived : F, Fallback {};

    template <typename C, C> struct ChT;

    template <typename C>
    static uint64_t f(ChT<void* Fallback::*, &C::utime>*, const F* msg)
    {
        return TimeUtil::utime();
    };
    template <typename C>
    static uint64_t f(void*, ...)
    {
        va_list args;
        va_start(args, 1);
        const F* msg = va_arg(args, const F*);
        va_end(args);
        return msg->utime;
    }

    static uint64_t const utime(const F* msg)
    {
        return f<Derived>(0,msg);
    }
};
// *****************************************************************************

template <typename T>
class MessageTracker
{
  public:
    typedef void (*callback)(const T* msg, void* usr);

  private:
    zcm::ZCM* zcmLocal = nullptr;

    std::atomic_bool done {false};

    Circular<T> *buf;
    std::mutex bufLock;
    std::condition_variable newMsg;
    zcm::Subscription *s;

    std::thread *thr = nullptr;
    callback onMsg;
    void* usr;

    uint64_t maxTimeErr_us;

    void callbackThreadFunc()
    {
        while (!done) {
            T* localMsg = get();
            if (done) return;
            onMsg(localMsg, usr);
        }
    }

    void handle(const zcm::ReceiveBuffer* rbuf, const std::string& chan, const T* _msg)
    {
        if (done)
            return;

        T* tmp = new T(*_msg);

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (buf->isFull())
                buf->removeFront();

            while (!buf->isEmpty()) {
                if (getMsgUtime(buf->front()) + maxTimeErr_us > getMsgUtime(_msg))
                    break;
                buf->removeFront();
            }

            buf->pushBack(tmp);
        }
        newMsg.notify_all();
    }

    MessageTracker() {}

  protected:
    virtual uint64_t getMsgUtime(const T* msg)
    {
        return hasUtime<T>::utime(msg);
    }

    virtual T* interpolate(uint64_t utimeTarget,
                           const T* A, uint64_t utimeA,
                           const T* B, uint64_t utimeB)
    {
        std::cout << "Interpolating" << std::endl;
        return utimeTarget - utimeA < utimeB - utimeTarget ? new T(*A) : new T(*B);
    }

  public:
    static const bool NONBLOCKING = false;
    static const bool BLOCKING = true;

    MessageTracker(zcm::ZCM* zcmLocal, std::string channel,
                   uint64_t maxTimeErr_us = 0.25e6, size_t maxMsgs = 1,
                   callback onMsg = nullptr, void* usr = nullptr)
        : zcmLocal(zcmLocal), maxTimeErr_us(maxTimeErr_us), onMsg(onMsg), usr(usr)
    {
        buf = new Circular<T>(maxMsgs);
        if (onMsg != nullptr)
            thr = new std::thread(&MessageTracker<T>::callbackThreadFunc, this);
        s = zcmLocal->subscribe(channel, &MessageTracker<T>::handle, this);
    }

    virtual ~MessageTracker()
    {
        zcmLocal->unsubscribe(s);
        done = true;
        newMsg.notify_all();
        if (thr) {
            thr->join();
            delete thr;
        }
        while (!buf->isEmpty())
            buf->removeFront();
        delete buf;
    }

    // You must free the memory returned here
    virtual T* get(bool blocking = NONBLOCKING)
    {
        T* ret = nullptr;

        {
            std::unique_lock<std::mutex> lk(bufLock);
            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }
            if (!buf->isEmpty())
                ret = new T(*buf->back());
        }

        return ret;
    }

    virtual T* get(uint64_t utime, bool blocking = NONBLOCKING)
    {
        T *m0 = nullptr, *m1 = nullptr; // two poses bracketing the desired utime
        uint64_t m0Utime, m1Utime;

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }

            size_t size = buf->size();

            const T *_m0 = nullptr;
            const T *_m1 = nullptr;

            for (size_t i = 0; i < size; ++i) {
                const T* m = (*buf)[i];
                uint64_t mUtime = getMsgUtime(m);

                if (mUtime <= utime && (_m0 == nullptr || mUtime > m0Utime)) {
                    _m0 = m;
                    m0Utime = getMsgUtime(_m0);
                }

                if (mUtime >= utime && (_m1 == nullptr || mUtime < m1Utime)) {
                    _m1 = m;
                    m1Utime = getMsgUtime(_m1);
                }
            }

            if (_m0 != nullptr)
                m0 = new T(*_m0);

            if (_m1 != nullptr)
                m1 = new T(*_m1);

        }

        if (m0 && utime - m0Utime > maxTimeErr_us) {
            delete m0;
            m0 = nullptr;
        }

        if (m1 && m1Utime - utime > maxTimeErr_us) {
            delete m1;
            m1 = nullptr;
        }

        if (m0 && m1) {
            if (m0Utime == m1Utime) {
                delete m1;
                return m0;
            }

            T* elt = interpolate(utime, m0, m0Utime, m1, m1Utime);

            delete m0;
            delete m1;

            return elt;
        }

        if (m0) return m0;
        if (m1) return m1;

        return nullptr;
    }
};
<commit_msg>inlined utime function<commit_after>#pragma once

#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <sys/time.h>
#include <stdarg.h>

#include <zcm/zcm-cpp.hpp>
#include <zcm/util/circular.hpp>

// *****************************************************************************
// Insanely hacky trick to determine at compile time if a zcmtype has a
// field called "utime"
template <typename F> struct hasUtime {
    struct Fallback { void* utime; }; // introduce member name "utime"
    struct Derived : F, Fallback {};

    template <typename C, C> struct ChT;

    template <typename C>
    static uint64_t f(ChT<void* Fallback::*, &C::utime>*, const F* msg)
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
    };
    template <typename C>
    static uint64_t f(void*, ...)
    {
        va_list args;
        va_start(args, 1);
        const F* msg = va_arg(args, const F*);
        va_end(args);
        return msg->utime;
    }

    static uint64_t const utime(const F* msg)
    {
        return f<Derived>(0,msg);
    }
};
// *****************************************************************************

template <typename T>
class MessageTracker
{
  public:
    typedef void (*callback)(const T* msg, void* usr);

  private:
    zcm::ZCM* zcmLocal = nullptr;

    std::atomic_bool done {false};

    Circular<T> *buf;
    std::mutex bufLock;
    std::condition_variable newMsg;
    zcm::Subscription *s;

    std::thread *thr = nullptr;
    callback onMsg;
    void* usr;

    uint64_t maxTimeErr_us;

    void callbackThreadFunc()
    {
        while (!done) {
            T* localMsg = get();
            if (done) return;
            onMsg(localMsg, usr);
        }
    }

    void handle(const zcm::ReceiveBuffer* rbuf, const std::string& chan, const T* _msg)
    {
        if (done)
            return;

        T* tmp = new T(*_msg);

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (buf->isFull())
                buf->removeFront();

            while (!buf->isEmpty()) {
                if (getMsgUtime(buf->front()) + maxTimeErr_us > getMsgUtime(_msg))
                    break;
                buf->removeFront();
            }

            buf->pushBack(tmp);
        }
        newMsg.notify_all();
    }

    MessageTracker() {}

  protected:
    virtual uint64_t getMsgUtime(const T* msg)
    {
        return hasUtime<T>::utime(msg);
    }

    virtual T* interpolate(uint64_t utimeTarget,
                           const T* A, uint64_t utimeA,
                           const T* B, uint64_t utimeB)
    {
        std::cout << "Interpolating" << std::endl;
        return utimeTarget - utimeA < utimeB - utimeTarget ? new T(*A) : new T(*B);
    }

  public:
    static const bool NONBLOCKING = false;
    static const bool BLOCKING = true;

    MessageTracker(zcm::ZCM* zcmLocal, std::string channel,
                   uint64_t maxTimeErr_us = 0.25e6, size_t maxMsgs = 1,
                   callback onMsg = nullptr, void* usr = nullptr)
        : zcmLocal(zcmLocal), maxTimeErr_us(maxTimeErr_us), onMsg(onMsg), usr(usr)
    {
        buf = new Circular<T>(maxMsgs);
        if (onMsg != nullptr)
            thr = new std::thread(&MessageTracker<T>::callbackThreadFunc, this);
        s = zcmLocal->subscribe(channel, &MessageTracker<T>::handle, this);
    }

    virtual ~MessageTracker()
    {
        zcmLocal->unsubscribe(s);
        done = true;
        newMsg.notify_all();
        if (thr) {
            thr->join();
            delete thr;
        }
        while (!buf->isEmpty())
            buf->removeFront();
        delete buf;
    }

    // You must free the memory returned here
    virtual T* get(bool blocking = NONBLOCKING)
    {
        T* ret = nullptr;

        {
            std::unique_lock<std::mutex> lk(bufLock);
            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }
            if (!buf->isEmpty())
                ret = new T(*buf->back());
        }

        return ret;
    }

    virtual T* get(uint64_t utime, bool blocking = NONBLOCKING)
    {
        T *m0 = nullptr, *m1 = nullptr; // two poses bracketing the desired utime
        uint64_t m0Utime, m1Utime;

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }

            size_t size = buf->size();

            const T *_m0 = nullptr;
            const T *_m1 = nullptr;

            for (size_t i = 0; i < size; ++i) {
                const T* m = (*buf)[i];
                uint64_t mUtime = getMsgUtime(m);

                if (mUtime <= utime && (_m0 == nullptr || mUtime > m0Utime)) {
                    _m0 = m;
                    m0Utime = getMsgUtime(_m0);
                }

                if (mUtime >= utime && (_m1 == nullptr || mUtime < m1Utime)) {
                    _m1 = m;
                    m1Utime = getMsgUtime(_m1);
                }
            }

            if (_m0 != nullptr)
                m0 = new T(*_m0);

            if (_m1 != nullptr)
                m1 = new T(*_m1);

        }

        if (m0 && utime - m0Utime > maxTimeErr_us) {
            delete m0;
            m0 = nullptr;
        }

        if (m1 && m1Utime - utime > maxTimeErr_us) {
            delete m1;
            m1 = nullptr;
        }

        if (m0 && m1) {
            if (m0Utime == m1Utime) {
                delete m1;
                return m0;
            }

            T* elt = interpolate(utime, m0, m0Utime, m1, m1Utime);

            delete m0;
            delete m1;

            return elt;
        }

        if (m0) return m0;
        if (m1) return m1;

        return nullptr;
    }
};
<|endoftext|>


<commit_before>#pragma once

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <typeinfo>
#include <cxxabi.h>
#include <sys/time.h>
#include <stdarg.h>

#include <zcm/zcm-cpp.hpp>
#include <zcm/util/circular.hpp>

static bool __ZCM_DEBUG_ENABLED__ = (NULL != getenv("ZCM_DEBUG"));
#define ZCM_DEBUG(...) \
    do { \
        if (__ZCM_DEBUG_ENABLED__) \
            __ZCM_PRINT_OBFUSCATE__(std::cout, "ZCM-DEBUG: ", __VA_ARGS__, '\n'); \
    } while(0)

namespace zcm {

template <typename T>
class MessageTracker
{
  public:
    typedef void (*callback)(T* msg, uint64_t utime, void* usr);
    static const bool NONBLOCKING = false;
    static const bool BLOCKING = true;

  protected:
    virtual uint64_t getMsgUtime(const T* msg)
    {
        return hasUtime<T>::utime(msg);
    }

    virtual T* interpolate(uint64_t utimeTarget,
                           const T* A, uint64_t utimeA,
                           const T* B, uint64_t utimeB)
    {
        return utimeTarget - utimeA < utimeB - utimeTarget ? new T(*A) : new T(*B);
    }

  private:
    zcm::ZCM* zcmLocal = nullptr;

    std::atomic_bool done {false};

    Circular<T> *buf;
    std::mutex bufLock;
    std::condition_variable newMsg;
    zcm::Subscription *s;

    std::mutex callbackLock;
    std::condition_variable callbackCv;
    T* callbackMsg = nullptr;
    std::thread *thr = nullptr;
    callback onMsg;
    void* usr;

    uint64_t maxTimeErr_us;

    void callbackThreadFunc()
    {
        std::unique_lock<std::mutex> lk(callbackLock);
        while (!done) {
            if (!callbackMsg) {
                callbackCv.wait(lk, [&](){ return callbackMsg != nullptr || done; });
                if (done) return;
            }
            onMsg(callbackMsg, getMsgUtime(callbackMsg), usr);
            // Intentionally not deleting callbackMsg as it is the
            // responsibility of the callback to delete the memory
            callbackMsg = nullptr;
        }
    }

    void handle(const zcm::ReceiveBuffer* rbuf, const std::string& chan, const T* _msg)
    {
        if (done)
            return;

        T* tmp = new T(*_msg);

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (buf->isFull())
                buf->removeFront();

            while (!buf->isEmpty()) {
                if (getMsgUtime(buf->front()) + maxTimeErr_us > getMsgUtime(_msg))
                    break;
                buf->removeFront();
            }

            buf->pushBack(tmp);
        }
        newMsg.notify_all();

        if (callbackLock.try_lock()) {
            if (callbackMsg) delete callbackMsg;
            callbackMsg = new T(*_msg);
            callbackLock.unlock();
            callbackCv.notify_all();
        }
    }

    MessageTracker() {}

  public:
    MessageTracker(zcm::ZCM* zcmLocal, std::string channel,
                   uint64_t maxTimeErr_us = 0.25e6, size_t maxMsgs = 1,
                   callback onMsg = nullptr, void* usr = nullptr)
        : zcmLocal(zcmLocal), maxTimeErr_us(maxTimeErr_us), onMsg(onMsg), usr(usr)
    {
        if (hasUtime<T>::present == true) {
            T tmp;
            std::string name = demangle(getType(tmp));
            ZCM_DEBUG("Message trackers using 'utime' field of zcmtype ", name);
        } else {
            T tmp;
            std::string name = demangle(getType(tmp));
            ZCM_DEBUG("Message trackers using local system receive utime for ",
                      "tracking zcmtype ", name);
        }
        buf = new Circular<T>(maxMsgs);
        if (onMsg != nullptr)
            thr = new std::thread(&MessageTracker<T>::callbackThreadFunc, this);
        s = zcmLocal->subscribe(channel, &MessageTracker<T>::handle, this);
    }

    virtual ~MessageTracker()
    {
        zcmLocal->unsubscribe(s);
        done = true;
        newMsg.notify_all();
        if (thr) {
            thr->join();
            delete thr;
        }
        while (!buf->isEmpty())
            buf->removeFront();
        delete buf;
    }

    // You must free the memory returned here
    virtual T* get(bool blocking = NONBLOCKING)
    {
        T* ret = nullptr;

        {
            std::unique_lock<std::mutex> lk(bufLock);
            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }
            if (!buf->isEmpty())
                ret = new T(*buf->back());
        }

        return ret;
    }

    virtual T* get(uint64_t utime, bool blocking = NONBLOCKING)
    {
        T *m0 = nullptr, *m1 = nullptr; // two poses bracketing the desired utime
        uint64_t m0Utime, m1Utime;

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }

            size_t size = buf->size();

            const T *_m0 = nullptr;
            const T *_m1 = nullptr;

            for (size_t i = 0; i < size; ++i) {
                const T* m = (*buf)[i];
                uint64_t mUtime = getMsgUtime(m);

                if (mUtime <= utime && (_m0 == nullptr || mUtime > m0Utime)) {
                    _m0 = m;
                    m0Utime = getMsgUtime(_m0);
                }

                if (mUtime >= utime && (_m1 == nullptr || mUtime < m1Utime)) {
                    _m1 = m;
                    m1Utime = getMsgUtime(_m1);
                }
            }

            if (_m0 != nullptr)
                m0 = new T(*_m0);

            if (_m1 != nullptr)
                m1 = new T(*_m1);

        }

        if (m0 && utime - m0Utime > maxTimeErr_us) {
            delete m0;
            m0 = nullptr;
        }

        if (m1 && m1Utime - utime > maxTimeErr_us) {
            delete m1;
            m1 = nullptr;
        }

        if (m0 && m1) {
            if (m0Utime == m1Utime) {
                delete m1;
                return m0;
            }

            T* elt = interpolate(utime, m0, m0Utime, m1, m1Utime);

            delete m0;
            delete m1;

            return elt;
        }

        if (m0) return m0;
        if (m1) return m1;

        return nullptr;
    }

  private:
    // *****************************************************************************
    // Insanely hacky trick to determine at compile time if a zcmtype has a
    // field called "utime"
    template <typename F> struct hasUtime {
        struct Fallback { void* utime; }; // introduce member name "utime"
        struct Derived : F, Fallback {};

        template <typename C, C> struct ChT;

        template <typename C>
        static uint64_t _utime(ChT<void* Fallback::*, &C::utime>*, const F* msg)
        {
            struct timeval tv;
            gettimeofday(&tv, NULL);
            return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
        };
        template <typename C>
        static uint64_t _utime(void*, ...)
        {
            va_list args;
            va_start(args, 1);
            const F* msg = va_arg(args, const F*);
            va_end(args);
            return msg->utime;
        }

        template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
        template<typename C> static char (&f(...))[2];

        static bool const present = sizeof(f<Derived>(0)) == 2;

        static uint64_t const utime(const F* msg)
        {
            return _utime<Derived>(0,msg);
        }
    };

    template<typename F>
    static inline std::string getType(const F t) { return typeid(t).name(); }

    static inline std::string demangle(std::string name)
    {
        int status = -4; // some arbitrary value to eliminate the compiler warning
        std::unique_ptr<char, void(*)(void*)> res {
            abi::__cxa_demangle(name.c_str(), NULL, NULL, &status),
            std::free
        };
        return (status==0) ? res.get() : name ;
    }

    static void __ZCM_PRINT_OBFUSCATE__(std::ostream& o) { }

    template<typename First, typename ...Rest>
    static void __ZCM_PRINT_OBFUSCATE__(std::ostream& o, First && first, Rest && ...rest)
    {
        o << std::forward<First>(first);
        __ZCM_PRINT_OBFUSCATE__(o, std::forward<Rest>(rest)...);
    }
    // *****************************************************************************

};

}

#undef ZCM_DEBUG
<commit_msg>More proper blocking in utime wait<commit_after>#pragma once

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <typeinfo>
#include <cxxabi.h>
#include <sys/time.h>
#include <stdarg.h>

#include <zcm/zcm-cpp.hpp>
#include <zcm/util/circular.hpp>

static bool __ZCM_DEBUG_ENABLED__ = (NULL != getenv("ZCM_DEBUG"));
#define ZCM_DEBUG(...) \
    do { \
        if (__ZCM_DEBUG_ENABLED__) \
            __ZCM_PRINT_OBFUSCATE__(std::cout, "ZCM-DEBUG: ", __VA_ARGS__, '\n'); \
    } while(0)

namespace zcm {

template <typename T>
class MessageTracker
{
  public:
    typedef void (*callback)(T* msg, uint64_t utime, void* usr);
    static const bool NONBLOCKING = false;
    static const bool BLOCKING = true;

  protected:
    virtual uint64_t getMsgUtime(const T* msg)
    {
        return hasUtime<T>::utime(msg);
    }

    virtual T* interpolate(uint64_t utimeTarget,
                           const T* A, uint64_t utimeA,
                           const T* B, uint64_t utimeB)
    {
        return utimeTarget - utimeA < utimeB - utimeTarget ? new T(*A) : new T(*B);
    }

  private:
    zcm::ZCM* zcmLocal = nullptr;

    std::atomic_bool done {false};

    Circular<T> *buf;
    std::mutex bufLock;
    std::condition_variable newMsg;
    zcm::Subscription *s;

    std::mutex callbackLock;
    std::condition_variable callbackCv;
    T* callbackMsg = nullptr;
    std::thread *thr = nullptr;
    callback onMsg;
    void* usr;

    uint64_t maxTimeErr_us;

    void callbackThreadFunc()
    {
        std::unique_lock<std::mutex> lk(callbackLock);
        while (!done) {
            if (!callbackMsg) {
                callbackCv.wait(lk, [&](){ return callbackMsg != nullptr || done; });
                if (done) return;
            }
            onMsg(callbackMsg, getMsgUtime(callbackMsg), usr);
            // Intentionally not deleting callbackMsg as it is the
            // responsibility of the callback to delete the memory
            callbackMsg = nullptr;
        }
    }

    void handle(const zcm::ReceiveBuffer* rbuf, const std::string& chan, const T* _msg)
    {
        if (done)
            return;

        T* tmp = new T(*_msg);

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (buf->isFull())
                buf->removeFront();

            while (!buf->isEmpty()) {
                if (getMsgUtime(buf->front()) + maxTimeErr_us > getMsgUtime(_msg))
                    break;
                buf->removeFront();
            }

            buf->pushBack(tmp);
        }
        newMsg.notify_all();

        if (callbackLock.try_lock()) {
            if (callbackMsg) delete callbackMsg;
            callbackMsg = new T(*_msg);
            callbackLock.unlock();
            callbackCv.notify_all();
        }
    }

    MessageTracker() {}

  public:
    MessageTracker(zcm::ZCM* zcmLocal, std::string channel,
                   uint64_t maxTimeErr_us = 0.25e6, size_t maxMsgs = 1,
                   callback onMsg = nullptr, void* usr = nullptr)
        : zcmLocal(zcmLocal), maxTimeErr_us(maxTimeErr_us), onMsg(onMsg), usr(usr)
    {
        if (hasUtime<T>::present == true) {
            T tmp;
            std::string name = demangle(getType(tmp));
            ZCM_DEBUG("Message trackers using 'utime' field of zcmtype ", name);
        } else {
            T tmp;
            std::string name = demangle(getType(tmp));
            ZCM_DEBUG("Message trackers using local system receive utime for ",
                      "tracking zcmtype ", name);
        }
        buf = new Circular<T>(maxMsgs);
        if (onMsg != nullptr)
            thr = new std::thread(&MessageTracker<T>::callbackThreadFunc, this);
        s = zcmLocal->subscribe(channel, &MessageTracker<T>::handle, this);
    }

    virtual ~MessageTracker()
    {
        zcmLocal->unsubscribe(s);
        done = true;
        newMsg.notify_all();
        if (thr) {
            thr->join();
            delete thr;
        }
        while (!buf->isEmpty())
            buf->removeFront();
        delete buf;
    }

    // You must free the memory returned here
    virtual T* get(bool blocking = NONBLOCKING)
    {
        T* ret = nullptr;

        {
            std::unique_lock<std::mutex> lk(bufLock);
            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }
            if (!buf->isEmpty())
                ret = new T(*buf->back());
        }

        return ret;
    }

    // This may return nullptr even in the blocking case
    virtual T* get(uint64_t utime, bool blocking = NONBLOCKING)
    {
        T *m0 = nullptr, *m1 = nullptr; // two poses bracketing the desired utime
        uint64_t m0Utime, m1Utime;

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (blocking == BLOCKING) {
                // XXX This is technically not okay. "done" can't be an
                //     atomic as it can change after we've checked it in the
                //     wait. If it does change, and we go back to sleep,
                //     we'll never wake up
                newMsg.wait(lk, [&]{
                            if (done) return true;
                            if (buf->isEmpty())
                                return false;
                            uint64_t recentUtime = getMsgUtime(buf->back());
                            if (recentUtime < utime)
                                return false;
                            return true;
                        });
                if (done) return nullptr;
            }

            size_t size = buf->size();

            const T *_m0 = nullptr;
            const T *_m1 = nullptr;

            for (size_t i = 0; i < size; ++i) {
                const T* m = (*buf)[i];
                uint64_t mUtime = getMsgUtime(m);

                if (mUtime <= utime && (_m0 == nullptr || mUtime > m0Utime)) {
                    _m0 = m;
                    m0Utime = getMsgUtime(_m0);
                }

                if (mUtime >= utime && (_m1 == nullptr || mUtime < m1Utime)) {
                    _m1 = m;
                    m1Utime = getMsgUtime(_m1);
                }
            }

            if (_m0 != nullptr)
                m0 = new T(*_m0);

            if (_m1 != nullptr)
                m1 = new T(*_m1);

        }

        if (m0 && utime - m0Utime > maxTimeErr_us) {
            delete m0;
            m0 = nullptr;
        }

        if (m1 && m1Utime - utime > maxTimeErr_us) {
            delete m1;
            m1 = nullptr;
        }

        if (m0 && m1) {
            if (m0Utime == m1Utime) {
                delete m1;
                return m0;
            }

            T* elt = interpolate(utime, m0, m0Utime, m1, m1Utime);

            delete m0;
            delete m1;

            return elt;
        }

        if (m0) return m0;
        if (m1) return m1;

        return nullptr;
    }

  private:
    // *****************************************************************************
    // Insanely hacky trick to determine at compile time if a zcmtype has a
    // field called "utime"
    template <typename F> struct hasUtime {
        struct Fallback { void* utime; }; // introduce member name "utime"
        struct Derived : F, Fallback {};

        template <typename C, C> struct ChT;

        template <typename C>
        static uint64_t _utime(ChT<void* Fallback::*, &C::utime>*, const F* msg)
        {
            struct timeval tv;
            gettimeofday(&tv, NULL);
            return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
        };
        template <typename C>
        static uint64_t _utime(void*, ...)
        {
            va_list args;
            va_start(args, 1);
            const F* msg = va_arg(args, const F*);
            va_end(args);
            return msg->utime;
        }

        template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
        template<typename C> static char (&f(...))[2];

        static bool const present = sizeof(f<Derived>(0)) == 2;

        static uint64_t const utime(const F* msg)
        {
            return _utime<Derived>(0,msg);
        }
    };

    template<typename F>
    static inline std::string getType(const F t) { return typeid(t).name(); }

    static inline std::string demangle(std::string name)
    {
        int status = -4; // some arbitrary value to eliminate the compiler warning
        std::unique_ptr<char, void(*)(void*)> res {
            abi::__cxa_demangle(name.c_str(), NULL, NULL, &status),
            std::free
        };
        return (status==0) ? res.get() : name ;
    }

    static void __ZCM_PRINT_OBFUSCATE__(std::ostream& o) { }

    template<typename First, typename ...Rest>
    static void __ZCM_PRINT_OBFUSCATE__(std::ostream& o, First && first, Rest && ...rest)
    {
        o << std::forward<First>(first);
        __ZCM_PRINT_OBFUSCATE__(o, std::forward<Rest>(rest)...);
    }
    // *****************************************************************************

};

}

#undef ZCM_DEBUG
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/selectors/dw_convolution_selector.h"

#include "absl/memory/memory.h"
#include "tensorflow/lite/delegates/gpu/cl/cl_device.h"
#include "tensorflow/lite/delegates/gpu/cl/kernels/depth_wise_conv.h"
#include "tensorflow/lite/delegates/gpu/cl/kernels/depth_wise_conv_3x3.h"

namespace tflite {
namespace gpu {
namespace cl {
namespace {

Status SelectDWConvolutionAdreno(const DepthwiseConvolution2DAttributes& attr,
                                 const CreationContext& creation_context,
                                 const OperationDef& op_def,
                                 std::unique_ptr<GPUOperation>* ptr) {
  if (IsDepthWiseConv3x3Supported(attr)) {
    DepthWiseConv3x3 dw_conv;
    RETURN_IF_ERROR(
        CreateDepthWiseConv3x3(creation_context, op_def, attr, &dw_conv));
    *ptr = absl::make_unique<DepthWiseConv3x3>(std::move(dw_conv));
  } else {
    DepthWiseConvolution dw_conv;
    RETURN_IF_ERROR(
        CreateDepthWiseConvolution(creation_context, op_def, attr, &dw_conv));
    *ptr = absl::make_unique<DepthWiseConvolution>(std::move(dw_conv));
  }
  return OkStatus();
}

Status SelectDWConvolutionPowerVR(const DepthwiseConvolution2DAttributes& attr,
                                 const CreationContext& creation_context,
                                 const OperationDef& op_def,
                                 std::unique_ptr<GPUOperation>* ptr) {
  if (IsDepthWiseConv3x3Supported(attr)) {
    DepthWiseConv3x3 dw_conv;
    RETURN_IF_ERROR(
        CreateDepthWiseConv3x3(creation_context, op_def, attr, &dw_conv));
    *ptr = absl::make_unique<DepthWiseConv3x3>(std::move(dw_conv));
  } else {
    DepthWiseConvolution dw_conv;
    RETURN_IF_ERROR(
        CreateDepthWiseConvolution(creation_context, op_def, attr, &dw_conv));
    *ptr = absl::make_unique<DepthWiseConvolution>(std::move(dw_conv));
  }
  return OkStatus();
}

Status SelectDWConvolutionMali(const DepthwiseConvolution2DAttributes& attr,
                                 const CreationContext& creation_context,
                                 const OperationDef& op_def,
                                 std::unique_ptr<GPUOperation>* ptr) {
  DepthWiseConvolution dw_conv;
  RETURN_IF_ERROR(
      CreateDepthWiseConvolution(creation_context, op_def, attr, &dw_conv));
  *ptr = absl::make_unique<DepthWiseConvolution>(std::move(dw_conv));
  return OkStatus();
}
}  // namespace

Status SelectDWConvolution(const DepthwiseConvolution2DAttributes& attr,
                           const CreationContext& creation_context,
                           const OperationDef& op_def,
                           std::unique_ptr<GPUOperation>* ptr) {
  switch (creation_context.device->vendor()) {
    case Vendor::QUALCOMM:
      return SelectDWConvolutionAdreno(attr, creation_context, op_def, ptr);
    case Vendor::POWERVR:
      return SelectDWConvolutionPowerVR(attr, creation_context, op_def, ptr);
    case Vendor::MALI:
      return SelectDWConvolutionMali(attr, creation_context, op_def, ptr);
    default:
      return SelectDWConvolutionAdreno(attr, creation_context, op_def, ptr);
  }
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Fixed selector for depthwise.<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/selectors/dw_convolution_selector.h"

#include "absl/memory/memory.h"
#include "tensorflow/lite/delegates/gpu/cl/cl_device.h"
#include "tensorflow/lite/delegates/gpu/cl/kernels/depth_wise_conv.h"
#include "tensorflow/lite/delegates/gpu/cl/kernels/depth_wise_conv_3x3.h"

namespace tflite {
namespace gpu {
namespace cl {
namespace {

Status SelectDWConvolutionAdreno(const DepthwiseConvolution2DAttributes& attr,
                                 const CreationContext& creation_context,
                                 const OperationDef& op_def,
                                 std::unique_ptr<GPUOperation>* ptr) {
  if (!op_def.batch_support && IsDepthWiseConv3x3Supported(attr)) {
    DepthWiseConv3x3 dw_conv;
    RETURN_IF_ERROR(
        CreateDepthWiseConv3x3(creation_context, op_def, attr, &dw_conv));
    *ptr = absl::make_unique<DepthWiseConv3x3>(std::move(dw_conv));
  } else {
    DepthWiseConvolution dw_conv;
    RETURN_IF_ERROR(
        CreateDepthWiseConvolution(creation_context, op_def, attr, &dw_conv));
    *ptr = absl::make_unique<DepthWiseConvolution>(std::move(dw_conv));
  }
  return OkStatus();
}

Status SelectDWConvolutionPowerVR(const DepthwiseConvolution2DAttributes& attr,
                                 const CreationContext& creation_context,
                                 const OperationDef& op_def,
                                 std::unique_ptr<GPUOperation>* ptr) {
  if (!op_def.batch_support && IsDepthWiseConv3x3Supported(attr)) {
    DepthWiseConv3x3 dw_conv;
    RETURN_IF_ERROR(
        CreateDepthWiseConv3x3(creation_context, op_def, attr, &dw_conv));
    *ptr = absl::make_unique<DepthWiseConv3x3>(std::move(dw_conv));
  } else {
    DepthWiseConvolution dw_conv;
    RETURN_IF_ERROR(
        CreateDepthWiseConvolution(creation_context, op_def, attr, &dw_conv));
    *ptr = absl::make_unique<DepthWiseConvolution>(std::move(dw_conv));
  }
  return OkStatus();
}

Status SelectDWConvolutionMali(const DepthwiseConvolution2DAttributes& attr,
                                 const CreationContext& creation_context,
                                 const OperationDef& op_def,
                                 std::unique_ptr<GPUOperation>* ptr) {
  DepthWiseConvolution dw_conv;
  RETURN_IF_ERROR(
      CreateDepthWiseConvolution(creation_context, op_def, attr, &dw_conv));
  *ptr = absl::make_unique<DepthWiseConvolution>(std::move(dw_conv));
  return OkStatus();
}
}  // namespace

Status SelectDWConvolution(const DepthwiseConvolution2DAttributes& attr,
                           const CreationContext& creation_context,
                           const OperationDef& op_def,
                           std::unique_ptr<GPUOperation>* ptr) {
  switch (creation_context.device->vendor()) {
    case Vendor::QUALCOMM:
      return SelectDWConvolutionAdreno(attr, creation_context, op_def, ptr);
    case Vendor::POWERVR:
      return SelectDWConvolutionPowerVR(attr, creation_context, op_def, ptr);
    case Vendor::MALI:
      return SelectDWConvolutionMali(attr, creation_context, op_def, ptr);
    default:
      return SelectDWConvolutionAdreno(attr, creation_context, op_def, ptr);
  }
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>/* Copyright (c) 2010, Cedrus Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of Cedrus Corporation nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "xid_con_t.h"
#include "constants.h"

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <IOKit/serial/ioss.h>
#include <termios.h>

#include <boost/date_time/posix_time/posix_time.hpp>

#include <iostream>

struct cedrus::xid_con_t::DarwinConnPimpl
{
    DarwinConnPimpl()
    : m_FileDescriptor ( 0 )
    {}

    int m_FileDescriptor;
    termios m_OptionsOriginal;
    termios	m_OptionsCurrent;
};

cedrus::xid_con_t::xid_con_t(
    const std::string &port_name,
    int port_speed,
    int delay_ms,
    bytesize byte_size,
    bitparity bit_parity,
    stopbits stop_bits
    )
    : baud_rate_(port_speed),
      byte_size_(byte_size),
      bit_parity_(bit_parity),
      stop_bits_(stop_bits),
      handshaking_(HANDSHAKE_NONE),
      port_name_(port_name),
      delay_(delay_ms),
      needs_interbyte_delay_(true),
      m_connection_dead (false),
      m_darwinPimpl( new DarwinConnPimpl )
{
}

cedrus::xid_con_t::~xid_con_t(void)
{
    if(m_darwinPimpl->m_FileDescriptor != 0)
        close();
}

bool cedrus::xid_con_t::close()
{
    bool status = (::close(m_darwinPimpl->m_FileDescriptor) != -1);
    m_darwinPimpl->m_FileDescriptor = 0;

    return status;
}

bool cedrus::xid_con_t::flush_input()
{
    return ( tcflush( m_darwinPimpl->m_FileDescriptor, TCIFLUSH ) == 0 );
}

bool cedrus::xid_con_t::flush_output()
{
    return ( tcflush( m_darwinPimpl->m_FileDescriptor, TCOFLUSH ) == 0 );
}

int cedrus::xid_con_t::open()
{
    int status = XID_NO_ERR;

    m_darwinPimpl->m_FileDescriptor = ::open(port_name_.c_str(), O_RDWR | O_NOCTTY /*| O_NONBLOCK | O_FSYNC*/ );

    if(m_darwinPimpl->m_FileDescriptor == -1)
    {
        m_darwinPimpl->m_FileDescriptor = 0;
        status = XID_PORT_NOT_AVAILABLE;
    }
    else
    {
        if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCEXCL) == -1)
        {
            status = XID_PORT_NOT_AVAILABLE;
        }
        else
        {
            if ( !setup_com_port() )
                status = XID_ERROR_SETTING_UP_PORT;
        }
    }

    return status;
}

bool cedrus::xid_con_t::setup_com_port()
{
	bool status = true;

	// http://developer.apple.com/documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/chapter_2_section_7.html#//apple_ref/doc/uid/TP40000972-TP30000384-CIHIAAFF

    // Get the current options and save them so we can restore the
    // default settings later.
    if (tcgetattr(m_darwinPimpl->m_FileDescriptor, &(m_darwinPimpl->m_OptionsOriginal)) == OS_FILE_ERROR)
        status = false;
    else
    {
        // The serial port attributes such as timeouts and baud rate are set by
        // modifying the termios structure and then calling tcsetattr to
        // cause the changes to take effect. Note that the
        // changes will not take effect without the tcsetattr() call.
        // See tcsetattr(4) ("man 4 tcsetattr") for details.

        m_darwinPimpl->m_OptionsCurrent = m_darwinPimpl->m_OptionsOriginal;
    }

	if ( status )
	{
		// Set raw input (non-canonical) mode, with reads blocking until either
		// a single character has been received or a one second timeout expires.
		// See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios")
		// for details.

		cfmakeraw(&(m_darwinPimpl->m_OptionsCurrent));
		// the following two settings cause reads to be non-blocking, despite
		// the fact that the port has been set to block
		m_darwinPimpl->m_OptionsCurrent.c_cc[VMIN] = 0;
		m_darwinPimpl->m_OptionsCurrent.c_cc[VTIME] = 0;

		m_darwinPimpl->m_OptionsCurrent.c_iflag = ( IGNBRK | IGNPAR );	/* input flags */

		m_darwinPimpl->m_OptionsCurrent.c_oflag = 0;	/* output flags */
		m_darwinPimpl->m_OptionsCurrent.c_cflag = 0;	/* control flags */

		tcflag_t flags = m_darwinPimpl->m_OptionsCurrent.c_cflag;

		flags |= ( CREAD | HUPCL | CLOCAL );

		switch ( handshaking_ )
		{
			case HANDSHAKE_XON_XOFF:
				m_darwinPimpl->m_OptionsCurrent.c_iflag |= ( IXON | IXOFF | IXANY );
				break;

			case HANDSHAKE_HARDWARE:
				flags |= CRTSCTS;	// CTS and RTS flow control of output
				break;

			case HANDSHAKE_NONE:
				m_darwinPimpl->m_OptionsCurrent.c_iflag &= ~( IXON | IXOFF | IXANY );
				flags &= ~ CRTSCTS;
				break;

			default:
				break;
		}

		flags &= ~( PARENB | PARODD );
		m_darwinPimpl->m_OptionsCurrent.c_iflag &= ~( INPCK | ISTRIP );
		switch ( bit_parity_ )
		{
			case BITPARITY_ODD:
				m_darwinPimpl->m_OptionsCurrent.c_iflag |= INPCK | ISTRIP;
				flags |= PARODD; // this sets the parity to odd -- even is the default
			case BITPARITY_EVEN:
				m_darwinPimpl->m_OptionsCurrent.c_iflag |= INPCK;
				flags |= PARENB; // this enables parity
				break;

			case BITPARITY_NONE:
				break;

			default:
				break;
		}

		// The baud rate, word length, and handshake options can be set as follows:

		flags &= ~CSIZE;
		switch ( byte_size_ )
		{
			case BYTESIZE_6:
				flags |= CS6;
				break;

			case BYTESIZE_7:
				flags |= CS7;
				break;

			case BYTESIZE_8:
				flags |= CS8;
				break;

			default:
				break;
		}

		if ( stop_bits_ == STOP_BIT_2 )
			flags |= CSTOPB;
		else
			flags &= ~CSTOPB;

		cfsetspeed(&(m_darwinPimpl->m_OptionsCurrent), baud_rate_);
		m_darwinPimpl->m_OptionsCurrent.c_cflag = ( flags );

		// Cause the new options to take effect immediately.
		usleep(10*1000);

		if (tcsetattr(m_darwinPimpl->m_FileDescriptor, TCSAFLUSH, &(m_darwinPimpl->m_OptionsCurrent)) == OS_FILE_ERROR)
			status = false;
	}

	if ( handshaking_ == HANDSHAKE_HARDWARE )
	{

		if ( status )
		{
			// To set the modem handshake lines, use the following ioctls.
			// See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
			if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCSDTR) == OS_FILE_ERROR)
				status = false;
		}

		if ( status )
		{
			// Clear Data Terminal Ready (DTR)
			if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCCDTR) == OS_FILE_ERROR)
				status = false;
		}

		unsigned long handshake = 0;

		if ( status )
		{
			handshake = TIOCM_DTR | TIOCM_DSR | TIOCM_RTS | TIOCM_CTS;
			// Set the modem lines depending on the bits set in handshake.
			if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCMSET, &handshake) == OS_FILE_ERROR)
				status = false;
		}

		if ( status )
		{
			// To read the state of the modem lines, use the following ioctl.
			// See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.

			// Store the state of the modem lines in handshake.
			if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCMGET, &handshake) == OS_FILE_ERROR)
				status = false;
		}
	} // handshaking

	// :whschultz:20070507
	// Found Apple documentation stating how to set the read latency on a standard serial port.
	// http://developer.apple.com/samplecode/SerialPortSample/listing2.html
    // http://developer.apple.com/library/mac/samplecode/SerialPortSample/index.html
#if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3)
	if ( status )
	{
		unsigned long mics = 1UL;

		// Set the receive latency in microseconds. Serial drivers use this value to determine how often to
		// dequeue characters received by the hardware. Most applications don't need to set this value: if an
		// app reads lines of characters, the app can't do anything until the line termination character has been
		// received anyway. The most common applications which are sensitive to read latency are MIDI and IrDA
		// applications.

		// set latency to 1 microsecond
		if (ioctl(m_darwinPimpl->m_FileDescriptor, IOSSDATALAT, &mics) == OS_FILE_ERROR) //does that actually happen??
			status = false;
	}
#endif

	if ( status )
	{
		flush_input();
		flush_output();
	}

	return status;
}

bool cedrus::xid_con_t::read(
    unsigned char *in_buffer,
    int bytes_to_read,
    int *bytes_read)
{
    int status = true;
    int read = ::read(m_darwinPimpl->m_FileDescriptor, in_buffer, bytes_to_read);

    if( read == -1)
        status = false;
    else
        *bytes_read = read;

    return status;
}

bool cedrus::xid_con_t::write(
    unsigned char * const in_buffer,
    int bytes_to_write,
    int *bytes_written)
{
    unsigned char *p = in_buffer;
    int status = true;
    int written = 0;

    if(needs_interbyte_delay_)
    {
        for(int i = 0; i < bytes_to_write && status; ++i)
        {
            ssize_t byte_count = ::write(m_darwinPimpl->m_FileDescriptor, p, 1);

            if( byte_count == -1)
            {
                status = false;
                if ( errno == ENXIO )
                    m_connection_dead = true;
                break;
            }

            written += byte_count;

            if(written == bytes_to_write)
                break;

            usleep(delay_*1000);

            ++p;
        }
        *bytes_written = written;
    }
    else
    {
        written = ::write(m_darwinPimpl->m_FileDescriptor, in_buffer, bytes_to_write);
        tcdrain(m_darwinPimpl->m_FileDescriptor);

        if( written == -1)
        {
            if ( errno == ENXIO )
                m_connection_dead = true;

            status = false;
        }
        else
            *bytes_written = written;
    }

    return status;
}
<commit_msg>Forgot to properly set the dead connection flag in the read function. A serious oversight.<commit_after>/* Copyright (c) 2010, Cedrus Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of Cedrus Corporation nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "xid_con_t.h"
#include "constants.h"

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <IOKit/serial/ioss.h>
#include <termios.h>

#include <boost/date_time/posix_time/posix_time.hpp>

#include <iostream>

struct cedrus::xid_con_t::DarwinConnPimpl
{
    DarwinConnPimpl()
    : m_FileDescriptor ( 0 )
    {}

    int m_FileDescriptor;
    termios m_OptionsOriginal;
    termios	m_OptionsCurrent;
};

cedrus::xid_con_t::xid_con_t(
    const std::string &port_name,
    int port_speed,
    int delay_ms,
    bytesize byte_size,
    bitparity bit_parity,
    stopbits stop_bits
    )
    : baud_rate_(port_speed),
      byte_size_(byte_size),
      bit_parity_(bit_parity),
      stop_bits_(stop_bits),
      handshaking_(HANDSHAKE_NONE),
      port_name_(port_name),
      delay_(delay_ms),
      needs_interbyte_delay_(true),
      m_connection_dead (false),
      m_darwinPimpl( new DarwinConnPimpl )
{
}

cedrus::xid_con_t::~xid_con_t(void)
{
    if(m_darwinPimpl->m_FileDescriptor != 0)
        close();
}

bool cedrus::xid_con_t::close()
{
    bool status = (::close(m_darwinPimpl->m_FileDescriptor) != -1);
    m_darwinPimpl->m_FileDescriptor = 0;

    return status;
}

bool cedrus::xid_con_t::flush_input()
{
    return ( tcflush( m_darwinPimpl->m_FileDescriptor, TCIFLUSH ) == 0 );
}

bool cedrus::xid_con_t::flush_output()
{
    return ( tcflush( m_darwinPimpl->m_FileDescriptor, TCOFLUSH ) == 0 );
}

int cedrus::xid_con_t::open()
{
    int status = XID_NO_ERR;

    m_darwinPimpl->m_FileDescriptor = ::open(port_name_.c_str(), O_RDWR | O_NOCTTY /*| O_NONBLOCK | O_FSYNC*/ );

    if(m_darwinPimpl->m_FileDescriptor == -1)
    {
        m_darwinPimpl->m_FileDescriptor = 0;
        status = XID_PORT_NOT_AVAILABLE;
    }
    else
    {
        if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCEXCL) == -1)
        {
            status = XID_PORT_NOT_AVAILABLE;
        }
        else
        {
            if ( !setup_com_port() )
                status = XID_ERROR_SETTING_UP_PORT;
        }
    }

    return status;
}

bool cedrus::xid_con_t::setup_com_port()
{
	bool status = true;

	// http://developer.apple.com/documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/chapter_2_section_7.html#//apple_ref/doc/uid/TP40000972-TP30000384-CIHIAAFF

    // Get the current options and save them so we can restore the
    // default settings later.
    if (tcgetattr(m_darwinPimpl->m_FileDescriptor, &(m_darwinPimpl->m_OptionsOriginal)) == OS_FILE_ERROR)
        status = false;
    else
    {
        // The serial port attributes such as timeouts and baud rate are set by
        // modifying the termios structure and then calling tcsetattr to
        // cause the changes to take effect. Note that the
        // changes will not take effect without the tcsetattr() call.
        // See tcsetattr(4) ("man 4 tcsetattr") for details.

        m_darwinPimpl->m_OptionsCurrent = m_darwinPimpl->m_OptionsOriginal;
    }

	if ( status )
	{
		// Set raw input (non-canonical) mode, with reads blocking until either
		// a single character has been received or a one second timeout expires.
		// See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios")
		// for details.

		cfmakeraw(&(m_darwinPimpl->m_OptionsCurrent));
		// the following two settings cause reads to be non-blocking, despite
		// the fact that the port has been set to block
		m_darwinPimpl->m_OptionsCurrent.c_cc[VMIN] = 0;
		m_darwinPimpl->m_OptionsCurrent.c_cc[VTIME] = 0;

		m_darwinPimpl->m_OptionsCurrent.c_iflag = ( IGNBRK | IGNPAR );	/* input flags */

		m_darwinPimpl->m_OptionsCurrent.c_oflag = 0;	/* output flags */
		m_darwinPimpl->m_OptionsCurrent.c_cflag = 0;	/* control flags */

		tcflag_t flags = m_darwinPimpl->m_OptionsCurrent.c_cflag;

		flags |= ( CREAD | HUPCL | CLOCAL );

		switch ( handshaking_ )
		{
			case HANDSHAKE_XON_XOFF:
				m_darwinPimpl->m_OptionsCurrent.c_iflag |= ( IXON | IXOFF | IXANY );
				break;

			case HANDSHAKE_HARDWARE:
				flags |= CRTSCTS;	// CTS and RTS flow control of output
				break;

			case HANDSHAKE_NONE:
				m_darwinPimpl->m_OptionsCurrent.c_iflag &= ~( IXON | IXOFF | IXANY );
				flags &= ~ CRTSCTS;
				break;

			default:
				break;
		}

		flags &= ~( PARENB | PARODD );
		m_darwinPimpl->m_OptionsCurrent.c_iflag &= ~( INPCK | ISTRIP );
		switch ( bit_parity_ )
		{
			case BITPARITY_ODD:
				m_darwinPimpl->m_OptionsCurrent.c_iflag |= INPCK | ISTRIP;
				flags |= PARODD; // this sets the parity to odd -- even is the default
			case BITPARITY_EVEN:
				m_darwinPimpl->m_OptionsCurrent.c_iflag |= INPCK;
				flags |= PARENB; // this enables parity
				break;

			case BITPARITY_NONE:
				break;

			default:
				break;
		}

		// The baud rate, word length, and handshake options can be set as follows:

		flags &= ~CSIZE;
		switch ( byte_size_ )
		{
			case BYTESIZE_6:
				flags |= CS6;
				break;

			case BYTESIZE_7:
				flags |= CS7;
				break;

			case BYTESIZE_8:
				flags |= CS8;
				break;

			default:
				break;
		}

		if ( stop_bits_ == STOP_BIT_2 )
			flags |= CSTOPB;
		else
			flags &= ~CSTOPB;

		cfsetspeed(&(m_darwinPimpl->m_OptionsCurrent), baud_rate_);
		m_darwinPimpl->m_OptionsCurrent.c_cflag = ( flags );

		// Cause the new options to take effect immediately.
		usleep(10*1000);

		if (tcsetattr(m_darwinPimpl->m_FileDescriptor, TCSAFLUSH, &(m_darwinPimpl->m_OptionsCurrent)) == OS_FILE_ERROR)
			status = false;
	}

	if ( handshaking_ == HANDSHAKE_HARDWARE )
	{

		if ( status )
		{
			// To set the modem handshake lines, use the following ioctls.
			// See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
			if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCSDTR) == OS_FILE_ERROR)
				status = false;
		}

		if ( status )
		{
			// Clear Data Terminal Ready (DTR)
			if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCCDTR) == OS_FILE_ERROR)
				status = false;
		}

		unsigned long handshake = 0;

		if ( status )
		{
			handshake = TIOCM_DTR | TIOCM_DSR | TIOCM_RTS | TIOCM_CTS;
			// Set the modem lines depending on the bits set in handshake.
			if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCMSET, &handshake) == OS_FILE_ERROR)
				status = false;
		}

		if ( status )
		{
			// To read the state of the modem lines, use the following ioctl.
			// See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.

			// Store the state of the modem lines in handshake.
			if (ioctl(m_darwinPimpl->m_FileDescriptor, TIOCMGET, &handshake) == OS_FILE_ERROR)
				status = false;
		}
	} // handshaking

	// :whschultz:20070507
	// Found Apple documentation stating how to set the read latency on a standard serial port.
	// http://developer.apple.com/samplecode/SerialPortSample/listing2.html
    // http://developer.apple.com/library/mac/samplecode/SerialPortSample/index.html
#if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3)
	if ( status )
	{
		unsigned long mics = 1UL;

		// Set the receive latency in microseconds. Serial drivers use this value to determine how often to
		// dequeue characters received by the hardware. Most applications don't need to set this value: if an
		// app reads lines of characters, the app can't do anything until the line termination character has been
		// received anyway. The most common applications which are sensitive to read latency are MIDI and IrDA
		// applications.

		// set latency to 1 microsecond
		if (ioctl(m_darwinPimpl->m_FileDescriptor, IOSSDATALAT, &mics) == OS_FILE_ERROR) //does that actually happen??
			status = false;
	}
#endif

	if ( status )
	{
		flush_input();
		flush_output();
	}

	return status;
}

bool cedrus::xid_con_t::read(
    unsigned char *in_buffer,
    int bytes_to_read,
    int *bytes_read)
{
    int status = true;
    int read = ::read(m_darwinPimpl->m_FileDescriptor, in_buffer, bytes_to_read);

    if( read == -1)
    {
        status = false;
        if ( errno == ENXIO )
            m_connection_dead = true;
    }
    else
        *bytes_read = read;

    return status;
}

bool cedrus::xid_con_t::write(
    unsigned char * const in_buffer,
    int bytes_to_write,
    int *bytes_written)
{
    unsigned char *p = in_buffer;
    int status = true;
    int written = 0;

    if(needs_interbyte_delay_)
    {
        for(int i = 0; i < bytes_to_write && status; ++i)
        {
            ssize_t byte_count = ::write(m_darwinPimpl->m_FileDescriptor, p, 1);

            if( byte_count == -1)
            {
                status = false;
                if ( errno == ENXIO )
                    m_connection_dead = true;
                break;
            }

            written += byte_count;

            if(written == bytes_to_write)
                break;

            usleep(delay_*1000);

            ++p;
        }
        *bytes_written = written;
    }
    else
    {
        written = ::write(m_darwinPimpl->m_FileDescriptor, in_buffer, bytes_to_write);
        tcdrain(m_darwinPimpl->m_FileDescriptor);

        if( written == -1)
        {
            if ( errno == ENXIO )
                m_connection_dead = true;

            status = false;
        }
        else
            *bytes_written = written;
    }

    return status;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: layerimport.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: rt $ $Date: 2004-07-13 08:14:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_FORMS_LAYERIMPORT_HXX_
#define _XMLOFF_FORMS_LAYERIMPORT_HXX_

#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HPP_
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#include <com/sun/star/container/XNameContainer.hpp>
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>
#endif
#ifndef _XMLOFF_FORMATTRIBUTES_HXX_
#include "formattributes.hxx"
#endif
#ifndef _XMLOFF_FORMS_CALLBACKS_HXX_
#include "callbacks.hxx"
#endif
#ifndef _XMLOFF_FORMS_EVENTIMPORT_HXX_
#include "eventimport.hxx"
#endif
#ifndef _REF_HXX
#include <tools/ref.hxx>
#endif

class SvXMLImport;
class SvXMLImportContext;
class XMLPropertyHandlerFactory;
class SvXMLImportPropertyMapper;
class XMLPropStyleContext;

SV_DECL_REF( SvXMLStylesContext );
    // unfortunately, we can't put this into our namespace, as the macro expands to (amongst others) a forward
    // declaration of the class name, which then would be in the namespace, too

//.........................................................................
namespace xmloff
{
//.........................................................................

    class OAttribute2Property;

    //=====================================================================
    //= ControlReference
    //=====================================================================
    /// a structure containing a property set (the referred control) and a string (the list of referring controls)
/*  struct ControlReference
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                    xReferredControl;
        ::rtl::OUString
                    sReferringControls;

        ControlReference(
                const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxReferredControl,
                const ::rtl::OUString& _rReferringControls)
            :xReferredControl(_rxReferredControl)
            ,sReferringControls(_rReferringControls)
        {
        }
    };
*/

    //=====================================================================
    //= OFormLayerXMLImport_Impl
    //=====================================================================
    class OFormLayerXMLImport_Impl
                :public OAttributeMetaData
                ,public IControlIdMap
                ,public IFormsImportContext
                ,public ODefaultEventAttacherManager
    {
        friend class OFormLayerXMLImport;

    protected:
        SvXMLImport&                        m_rImporter;
        OAttribute2Property                 m_aAttributeMetaData;
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
                                            m_xForms;   // the forms of the currently imported page
        SvXMLStylesContext*                 m_pAutoStyles;

    protected:
        // style handling
        ::vos::ORef< XMLPropertyHandlerFactory >    m_xPropertyHandlerFactory;
        ::vos::ORef< SvXMLImportPropertyMapper >    m_xImportMapper;

        DECLARE_STL_USTRINGACCESS_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >, MapString2PropertySet );
        DECLARE_STL_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >, MapString2PropertySet, ODrawPageCompare, MapDrawPage2Map);

        MapDrawPage2Map         m_aControlIds;          // ids of the controls on all known page
        MapDrawPage2MapIterator m_aCurrentPageIds;      // ifs of the controls on the current page

        typedef ::std::pair< ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >, ::rtl::OUString >
                                ModelStringPair;
        ::std::vector< ModelStringPair >
                                m_aControlReferences;   // control reference descriptions for current page
        ::std::vector< ModelStringPair >
                                m_aCellValueBindings;   // information about controls bound to spreadsheet cells
        ::std::vector< ModelStringPair >
                                m_aCellRangeListSources;// information about controls bound to spreadsheet cell range list sources

    public:
        // IControlIdMap
        virtual void    registerControlId(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControl,
            const ::rtl::OUString& _rId);
        virtual void    registerControlReferences(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControl,
            const ::rtl::OUString& _rReferringControls);

        // IFormsImportContext
        virtual IControlIdMap&              getControlIdMap();
        virtual OAttribute2Property&        getAttributeMap();
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                                            getServiceFactory();
        virtual SvXMLImport&                getGlobalContext();
        const SvXMLStyleContext*            getStyleElement(const ::rtl::OUString& _rStyleName) const;
        virtual void                        enterEventContext();
        virtual void                        leaveEventContext();
        void                                applyControlNumberStyle(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rControlNumerStyleName
        );
        virtual void                        registerCellValueBinding(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rCellAddress
        );

        virtual void                        registerCellRangeListSource(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rCellRangeAddress
        );

    protected:
        OFormLayerXMLImport_Impl(SvXMLImport& _rImporter);
        ~OFormLayerXMLImport_Impl();

        /** retrieves the property mapper form form related auto styles.
        */
        ::vos::ORef< SvXMLImportPropertyMapper > getStylePropertyMapper() const;

        /** start importing the forms of the given page
        */
        void startPage(
            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& _rxDrawPage);

        /** end importing the forms of the current page
        */
        void endPage();

        /** creates an import context for the office:forms element
        */
        SvXMLImportContext* createOfficeFormsContext(
            SvXMLImport& _rImport,
            sal_uInt16 _nPrefix,
            const rtl::OUString& _rLocalName);

        /** create an <type>SvXMLImportContext</type> instance which is able to import the <form:form>
            element.
        */
        SvXMLImportContext* createContext(
            const sal_uInt16 _nPrefix,
            const rtl::OUString& _rLocalName,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& _rxAttribs);

        /** get the control with the given id
        */
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                lookupControlId(const ::rtl::OUString& _rControlId);

        /** seek to the given page
        */
        void seekPage(
            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& _rxDrawPage);

        /** announces the auto-style context to the form importer
        */
        void setAutoStyleContext(SvXMLStylesContext* _pNewContext);

        /** to be called when the document has been completely imported

For some documents (currently: only some spreadsheet documents) it's necessary
            do to a post processing, since not all information from the file can be processed
            if the document is not completed, yet.

        */
        void documentDone( );
    };

//.........................................................................
}   // namespace xmloff
//.........................................................................

#endif // _XMLOFF_FORMS_LAYERIMPORT_HXX_

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *  Revision 1.12.66.1  2004/06/08 14:49:18  mib
 *  - #i20153#: form controls
 *
 *  Revision 1.12  2003/12/01 12:04:46  rt
 *  INTEGRATION: CWS geordi2q09 (1.11.24); FILE MERGED
 *  2003/11/24 15:19:46 obo 1.11.24.2: undo last change
 *  2003/11/21 17:04:39 obo 1.11.24.1: #111934# join CWS comboboxlink
 *
 *  Revision 1.11.24.2  2003/11/24 15:19:46  obo
 *  undo last change
 *
 *  Revision 1.11  2003/10/21 08:40:18  obo
 *  INTEGRATION: CWS formcelllinkage (1.10.160); FILE MERGED
 *  2003/10/01 09:55:23 fs 1.10.160.1: #i18994# merging the changes from the CWS fs002
 *
 *  Revision 1.10.160.1  2003/10/01 09:55:23  fs
 *  #i18994# merging the changes from the CWS fs002
 *
 *  Revision 1.10.156.1  2003/09/25 14:28:41  fs
 *  #18994# merging the changes from cws_srx645_fs002 branch
 *
 *  Revision 1.10.152.1  2003/09/17 12:26:56  fs
 *  #18999# #19367# persistence for cell value and cell range bindings
 *
 *  Revision 1.10  2002/10/25 13:17:04  fs
 *  #104402# importing grid column styles now
 *
 *  Revision 1.9  2001/05/28 14:59:18  fs
 *  #86712# added control number style related functionality
 *
 *  Revision 1.8  2001/03/20 13:39:58  fs
 *  #83970# +createOfficeFormsContext
 *
 *  Revision 1.7  2001/02/01 09:46:47  fs
 *  no own style handling anymore - the shape exporter is responsible for our styles now
 *
 *  Revision 1.6  2001/01/24 09:34:40  fs
 *  +enter-/leaveEventContext
 *
 *  Revision 1.5  2001/01/02 15:58:22  fs
 *  event ex- & import
 *
 *  Revision 1.4  2000/12/18 15:14:35  fs
 *  some changes ... now exporting/importing styles
 *
 *  Revision 1.3  2000/12/13 10:40:15  fs
 *  new import related implementations - at this version, we should be able to import everything we export (which is all except events and styles)
 *
 *  Revision 1.2  2000/12/12 12:01:05  fs
 *  new implementations for the import - still under construction
 *
 *  Revision 1.1  2000/12/06 17:31:42  fs
 *  initial checkin - implementations for formlayer import/export - still under construction
 *
 *
 *  Revision 1.0 04.12.00 15:48:40  fs
 ************************************************************************/

<commit_msg>INTEGRATION: CWS insight01 (1.12.20); FILE MERGED 2004/07/23 13:22:53 oj 1.12.20.2: RESYNC: (1.12-1.13); FILE MERGED 2004/02/20 11:15:31 oj 1.12.20.1: #i25414# extend form file format for form:datasource<commit_after>/*************************************************************************
 *
 *  $RCSfile: layerimport.hxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: hr $ $Date: 2004-08-02 14:15:02 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_FORMS_LAYERIMPORT_HXX_
#define _XMLOFF_FORMS_LAYERIMPORT_HXX_

#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HPP_
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#include <com/sun/star/container/XNameContainer.hpp>
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>
#endif
#ifndef _XMLOFF_FORMATTRIBUTES_HXX_
#include "formattributes.hxx"
#endif
#ifndef _XMLOFF_FORMS_CALLBACKS_HXX_
#include "callbacks.hxx"
#endif
#ifndef _XMLOFF_FORMS_EVENTIMPORT_HXX_
#include "eventimport.hxx"
#endif
#ifndef _REF_HXX
#include <tools/ref.hxx>
#endif

class SvXMLImport;
class SvXMLImportContext;
class XMLPropertyHandlerFactory;
class SvXMLImportPropertyMapper;
class XMLPropStyleContext;

SV_DECL_REF( SvXMLStylesContext );
    // unfortunately, we can't put this into our namespace, as the macro expands to (amongst others) a forward
    // declaration of the class name, which then would be in the namespace, too

//.........................................................................
namespace xmloff
{
//.........................................................................

    class OAttribute2Property;

    //=====================================================================
    //= ControlReference
    //=====================================================================
    /// a structure containing a property set (the referred control) and a string (the list of referring controls)
/*  struct ControlReference
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                    xReferredControl;
        ::rtl::OUString
                    sReferringControls;

        ControlReference(
                const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxReferredControl,
                const ::rtl::OUString& _rReferringControls)
            :xReferredControl(_rxReferredControl)
            ,sReferringControls(_rReferringControls)
        {
        }
    };
*/

    //=====================================================================
    //= OFormLayerXMLImport_Impl
    //=====================================================================
    class OFormLayerXMLImport_Impl
                :public IControlIdMap
                ,public IFormsImportContext
                ,public ODefaultEventAttacherManager
    {
        friend class OFormLayerXMLImport;

    protected:
        SvXMLImport&                        m_rImporter;
        OAttribute2Property                 m_aAttributeMetaData;
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
                                            m_xForms;   // the forms of the currently imported page
        SvXMLStylesContext*                 m_pAutoStyles;

    protected:
        // style handling
        ::vos::ORef< XMLPropertyHandlerFactory >    m_xPropertyHandlerFactory;
        ::vos::ORef< SvXMLImportPropertyMapper >    m_xImportMapper;

        DECLARE_STL_USTRINGACCESS_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >, MapString2PropertySet );
        DECLARE_STL_MAP( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >, MapString2PropertySet, ODrawPageCompare, MapDrawPage2Map);

        MapDrawPage2Map         m_aControlIds;          // ids of the controls on all known page
        MapDrawPage2MapIterator m_aCurrentPageIds;      // ifs of the controls on the current page

        typedef ::std::pair< ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >, ::rtl::OUString >
                                ModelStringPair;
        ::std::vector< ModelStringPair >
                                m_aControlReferences;   // control reference descriptions for current page
        ::std::vector< ModelStringPair >
                                m_aCellValueBindings;   // information about controls bound to spreadsheet cells
        ::std::vector< ModelStringPair >
                                m_aCellRangeListSources;// information about controls bound to spreadsheet cell range list sources

    public:
        // IControlIdMap
        virtual void    registerControlId(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControl,
            const ::rtl::OUString& _rId);
        virtual void    registerControlReferences(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControl,
            const ::rtl::OUString& _rReferringControls);

        // IFormsImportContext
        virtual IControlIdMap&              getControlIdMap();
        virtual OAttribute2Property&        getAttributeMap();
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                                            getServiceFactory();
        virtual SvXMLImport&                getGlobalContext();
        const SvXMLStyleContext*            getStyleElement(const ::rtl::OUString& _rStyleName) const;
        virtual void                        enterEventContext();
        virtual void                        leaveEventContext();
        void                                applyControlNumberStyle(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rControlNumerStyleName
        );
        virtual void                        registerCellValueBinding(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rCellAddress
        );

        virtual void                        registerCellRangeListSource(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxControlModel,
            const ::rtl::OUString& _rCellRangeAddress
        );

    protected:
        OFormLayerXMLImport_Impl(SvXMLImport& _rImporter);
        ~OFormLayerXMLImport_Impl();

        /** retrieves the property mapper form form related auto styles.
        */
        ::vos::ORef< SvXMLImportPropertyMapper > getStylePropertyMapper() const;

        /** start importing the forms of the given page
        */
        void startPage(
            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& _rxDrawPage);

        /** end importing the forms of the current page
        */
        void endPage();

        /** creates an import context for the office:forms element
        */
        SvXMLImportContext* createOfficeFormsContext(
            SvXMLImport& _rImport,
            sal_uInt16 _nPrefix,
            const rtl::OUString& _rLocalName);

        /** create an <type>SvXMLImportContext</type> instance which is able to import the <form:form>
            element.
        */
        SvXMLImportContext* createContext(
            const sal_uInt16 _nPrefix,
            const rtl::OUString& _rLocalName,
            const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& _rxAttribs);

        /** get the control with the given id
        */
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                lookupControlId(const ::rtl::OUString& _rControlId);

        /** seek to the given page
        */
        void seekPage(
            const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& _rxDrawPage);

        /** announces the auto-style context to the form importer
        */
        void setAutoStyleContext(SvXMLStylesContext* _pNewContext);

        /** to be called when the document has been completely imported

For some documents (currently: only some spreadsheet documents) it's necessary
            do to a post processing, since not all information from the file can be processed
            if the document is not completed, yet.

        */
        void documentDone( );
    };

//.........................................................................
}   // namespace xmloff
//.........................................................................

#endif // _XMLOFF_FORMS_LAYERIMPORT_HXX_

<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2019 LibRaw LLC (info@libraw.org)
    Copyright (C) 2020 Roman Lebedev

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/PanasonicDecompressorV6.h" // for PanasonicDecompre...
#include "common/Array2DRef.h"                     // for Array2DRef
#include "common/Point.h"                          // for iPoint2D
#include "common/RawImage.h"                       // for RawImage, RawImag...
#include "decoders/RawDecoderException.h"          // for ThrowRDE
#include <algorithm>                               // for copy_n
#include <array>
#include <cstdint> // for uint16_t, uint32_t
#include <cstdlib> // for free, malloc

namespace rawspeed {

constexpr int PanasonicDecompressorV6::PixelsPerBlock;
constexpr int PanasonicDecompressorV6::BytesPerBlock;

namespace {
struct pana_cs6_page_decoder {
  std::array<unsigned int, 14> pixelbuffer;
  unsigned char current = 0;

  explicit pana_cs6_page_decoder(ByteStream bs) {
    auto wbuffer = [&](int i) {
      return static_cast<uint16_t>(bs.peekByte(15 - i));
    };
    pixelbuffer[0] = (wbuffer(0) << 6) | (wbuffer(1) >> 2); // 14 bit
    pixelbuffer[1] =
        (((wbuffer(1) & 0x3) << 12) | (wbuffer(2) << 4) | (wbuffer(3) >> 4)) &
        0x3fff;
    pixelbuffer[2] = (wbuffer(3) >> 2) & 0x3;
    pixelbuffer[3] = ((wbuffer(3) & 0x3) << 8) | wbuffer(4);
    pixelbuffer[4] = (wbuffer(5) << 2) | (wbuffer(6) >> 6);
    pixelbuffer[5] = ((wbuffer(6) & 0x3f) << 4) | (wbuffer(7) >> 4);
    pixelbuffer[6] = (wbuffer(7) >> 2) & 0x3;
    pixelbuffer[7] = ((wbuffer(7) & 0x3) << 8) | wbuffer(8);
    pixelbuffer[8] = ((wbuffer(9) << 2) & 0x3fc) | (wbuffer(10) >> 6);
    pixelbuffer[9] = ((wbuffer(10) << 4) | (wbuffer(11) >> 4)) & 0x3ff;
    pixelbuffer[10] = (wbuffer(11) >> 2) & 0x3;
    pixelbuffer[11] = ((wbuffer(11) & 0x3) << 8) | wbuffer(12);
    pixelbuffer[12] = (((wbuffer(13) << 2) & 0x3fc) | wbuffer(14) >> 6) & 0x3ff;
    pixelbuffer[13] = ((wbuffer(14) << 4) | (wbuffer(15) >> 4)) & 0x3ff;
  }

  unsigned int nextpixel() { return pixelbuffer[current++]; }
};
} // namespace

PanasonicDecompressorV6::PanasonicDecompressorV6(const RawImage& img,
                                                 ByteStream input_)
    : mRaw(img), input(std::move(input_)) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != sizeof(uint16_t))
    ThrowRDE("Unexpected component count / data type");

  if (!mRaw->dim.hasPositiveArea()) {
    ThrowRDE("Unexpected image dimensions found: (%i; %i)", mRaw->dim.x,
             mRaw->dim.y);
  }

  const int blocksperrow =
      mRaw->dim.x / PanasonicDecompressorV6::PixelsPerBlock;
  const int bytesPerRow = PanasonicDecompressorV6::BytesPerBlock * blocksperrow;
  const int bytesTotal = bytesPerRow * mRaw->dim.y;
  input = input_.peekStream(bytesTotal);
}

void PanasonicDecompressorV6::decompressBlock(ByteStream* rowInput, int row,
                                              int col) const {
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());

  pana_cs6_page_decoder page(
      rowInput->getStream(PanasonicDecompressorV6::BytesPerBlock));

  std::array<unsigned int, 2> oddeven = {0, 0};
  std::array<unsigned int, 2> nonzero = {0, 0};
  unsigned pmul = 0;
  unsigned pixel_base = 0;
  for (int pix = 0; pix < PanasonicDecompressorV6::PixelsPerBlock;
       pix++, col++) {
    if (pix % 3 == 2) {
      unsigned base = page.nextpixel();
      if (base > 3)
        ThrowRDE("Invariant failure");
      if (base == 3)
        base = 4;
      pixel_base = 0x200 << base;
      pmul = 1 << base;
    }
    unsigned epixel = page.nextpixel();
    if (oddeven[pix % 2]) {
      epixel *= pmul;
      if (pixel_base < 0x2000 && nonzero[pix % 2] > pixel_base)
        epixel += nonzero[pix % 2] - pixel_base;
      nonzero[pix % 2] = epixel;
    } else {
      oddeven[pix % 2] = epixel;
      if (epixel)
        nonzero[pix % 2] = epixel;
      else
        epixel = nonzero[pix % 2];
    }
    auto spix = static_cast<unsigned>(static_cast<int>(epixel) - 0xf);
    if (spix <= 0xffff)
      out(row, col) = spix & 0xffff;
    else {
      epixel = static_cast<signed int>(epixel + 0x7ffffff1) >> 0x1f;
      out(row, col) = epixel & 0x3fff;
    }
  }
}

void PanasonicDecompressorV6::decompressRow(int row) const {
  const int blocksperrow =
      mRaw->dim.x / PanasonicDecompressorV6::PixelsPerBlock;
  const int bytesPerRow = PanasonicDecompressorV6::BytesPerBlock * blocksperrow;

  ByteStream rowInput = input.getSubStream(bytesPerRow * row, bytesPerRow);
  for (int rblock = 0, col = 0; rblock < blocksperrow;
       rblock++, col += PanasonicDecompressorV6::PixelsPerBlock)
    decompressBlock(&rowInput, row, col);
}

void PanasonicDecompressorV6::decompress() const {
#ifdef HAVE_OPENMP
#pragma omp parallel for num_threads(rawspeed_get_number_of_processor_cores()) \
    schedule(static) default(none)
#endif
  for (int row = 0; row < mRaw->dim.y; ++row) {
    try {
      decompressRow(row);
    } catch (RawspeedException& err) {
      // Propagate the exception out of OpenMP magic.
      mRaw->setError(err.what());
    }
  }

  std::string firstErr;
  if (mRaw->isTooManyErrors(1, &firstErr)) {
    ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
             firstErr.c_str());
  }
}

} // namespace rawspeed
<commit_msg>PanasonicDecompressorV6: get rid of lambda, it's not helping here<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2019 LibRaw LLC (info@libraw.org)
    Copyright (C) 2020 Roman Lebedev

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/PanasonicDecompressorV6.h" // for PanasonicDecompre...
#include "common/Array2DRef.h"                     // for Array2DRef
#include "common/Point.h"                          // for iPoint2D
#include "common/RawImage.h"                       // for RawImage, RawImag...
#include "decoders/RawDecoderException.h"          // for ThrowRDE
#include <algorithm>                               // for copy_n
#include <array>
#include <cstdint> // for uint16_t, uint32_t
#include <cstdlib> // for free, malloc

namespace rawspeed {

constexpr int PanasonicDecompressorV6::PixelsPerBlock;
constexpr int PanasonicDecompressorV6::BytesPerBlock;

namespace {
struct pana_cs6_page_decoder {
  std::array<unsigned int, 14> pixelbuffer;
  unsigned char current = 0;

  explicit pana_cs6_page_decoder(const ByteStream& bs) {
    pixelbuffer[0] = (bs.peekByte(15) << 6) | (bs.peekByte(14) >> 2); // 14 bit
    pixelbuffer[1] = (((bs.peekByte(14) & 0x3) << 12) | (bs.peekByte(13) << 4) |
                      (bs.peekByte(12) >> 4)) &
                     0x3fff;
    pixelbuffer[2] = (bs.peekByte(12) >> 2) & 0x3;
    pixelbuffer[3] = ((bs.peekByte(12) & 0x3) << 8) | bs.peekByte(11);
    pixelbuffer[4] = (bs.peekByte(10) << 2) | (bs.peekByte(9) >> 6);
    pixelbuffer[5] = ((bs.peekByte(9) & 0x3f) << 4) | (bs.peekByte(8) >> 4);
    pixelbuffer[6] = (bs.peekByte(8) >> 2) & 0x3;
    pixelbuffer[7] = ((bs.peekByte(8) & 0x3) << 8) | bs.peekByte(7);
    pixelbuffer[8] = ((bs.peekByte(6) << 2) & 0x3fc) | (bs.peekByte(5) >> 6);
    pixelbuffer[9] = ((bs.peekByte(5) << 4) | (bs.peekByte(4) >> 4)) & 0x3ff;
    pixelbuffer[10] = (bs.peekByte(4) >> 2) & 0x3;
    pixelbuffer[11] = ((bs.peekByte(4) & 0x3) << 8) | bs.peekByte(3);
    pixelbuffer[12] =
        (((bs.peekByte(2) << 2) & 0x3fc) | bs.peekByte(1) >> 6) & 0x3ff;
    pixelbuffer[13] = ((bs.peekByte(1) << 4) | (bs.peekByte(0) >> 4)) & 0x3ff;
  }

  unsigned int nextpixel() { return pixelbuffer[current++]; }
};
} // namespace

PanasonicDecompressorV6::PanasonicDecompressorV6(const RawImage& img,
                                                 ByteStream input_)
    : mRaw(img), input(std::move(input_)) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != sizeof(uint16_t))
    ThrowRDE("Unexpected component count / data type");

  if (!mRaw->dim.hasPositiveArea()) {
    ThrowRDE("Unexpected image dimensions found: (%i; %i)", mRaw->dim.x,
             mRaw->dim.y);
  }

  const int blocksperrow =
      mRaw->dim.x / PanasonicDecompressorV6::PixelsPerBlock;
  const int bytesPerRow = PanasonicDecompressorV6::BytesPerBlock * blocksperrow;
  const int bytesTotal = bytesPerRow * mRaw->dim.y;
  input = input_.peekStream(bytesTotal);
}

void PanasonicDecompressorV6::decompressBlock(ByteStream* rowInput, int row,
                                              int col) const {
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());

  pana_cs6_page_decoder page(
      rowInput->getStream(PanasonicDecompressorV6::BytesPerBlock));

  std::array<unsigned int, 2> oddeven = {0, 0};
  std::array<unsigned int, 2> nonzero = {0, 0};
  unsigned pmul = 0;
  unsigned pixel_base = 0;
  for (int pix = 0; pix < PanasonicDecompressorV6::PixelsPerBlock;
       pix++, col++) {
    if (pix % 3 == 2) {
      unsigned base = page.nextpixel();
      if (base > 3)
        ThrowRDE("Invariant failure");
      if (base == 3)
        base = 4;
      pixel_base = 0x200 << base;
      pmul = 1 << base;
    }
    unsigned epixel = page.nextpixel();
    if (oddeven[pix % 2]) {
      epixel *= pmul;
      if (pixel_base < 0x2000 && nonzero[pix % 2] > pixel_base)
        epixel += nonzero[pix % 2] - pixel_base;
      nonzero[pix % 2] = epixel;
    } else {
      oddeven[pix % 2] = epixel;
      if (epixel)
        nonzero[pix % 2] = epixel;
      else
        epixel = nonzero[pix % 2];
    }
    auto spix = static_cast<unsigned>(static_cast<int>(epixel) - 0xf);
    if (spix <= 0xffff)
      out(row, col) = spix & 0xffff;
    else {
      epixel = static_cast<signed int>(epixel + 0x7ffffff1) >> 0x1f;
      out(row, col) = epixel & 0x3fff;
    }
  }
}

void PanasonicDecompressorV6::decompressRow(int row) const {
  const int blocksperrow =
      mRaw->dim.x / PanasonicDecompressorV6::PixelsPerBlock;
  const int bytesPerRow = PanasonicDecompressorV6::BytesPerBlock * blocksperrow;

  ByteStream rowInput = input.getSubStream(bytesPerRow * row, bytesPerRow);
  for (int rblock = 0, col = 0; rblock < blocksperrow;
       rblock++, col += PanasonicDecompressorV6::PixelsPerBlock)
    decompressBlock(&rowInput, row, col);
}

void PanasonicDecompressorV6::decompress() const {
#ifdef HAVE_OPENMP
#pragma omp parallel for num_threads(rawspeed_get_number_of_processor_cores()) \
    schedule(static) default(none)
#endif
  for (int row = 0; row < mRaw->dim.y; ++row) {
    try {
      decompressRow(row);
    } catch (RawspeedException& err) {
      // Propagate the exception out of OpenMP magic.
      mRaw->setError(err.what());
    }
  }

  std::string firstErr;
  if (mRaw->isTooManyErrors(1, &firstErr)) {
    ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
             firstErr.c_str());
  }
}

} // namespace rawspeed
<|endoftext|>