<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Trolltech ASA
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.

*/
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "factory_p.h"
#include "objectdescription.h"
#include "audiooutputadaptor_p.h"
#include "globalconfig_p.h"
#include "audiooutputinterface.h"
#include "phononnamespace_p.h"
#include "platform_p.h"

#include <qmath.h>

#define PHONON_CLASSNAME AudioOutput
#define IFACES2 AudioOutputInterface42
#define IFACES1 IFACES2
#define IFACES0 AudioOutputInterface40, IFACES1
#define PHONON_INTERFACENAME IFACES0

QT_BEGIN_NAMESPACE

namespace Phonon
{

static inline bool callSetOutputDevice(MediaNodePrivate *const d, int index)
{
    Iface<IFACES2> iface(d);
    if (iface) {
        return iface->setOutputDevice(AudioOutputDevice::fromIndex(index));
    }
    return Iface<IFACES0>::cast(d)->setOutputDevice(index);
}

static inline bool callSetOutputDevice(MediaNodePrivate *const d, const AudioOutputDevice &dev)
{
    Iface<IFACES2> iface(d);
    if (iface) {
        return iface->setOutputDevice(dev);
    }
    return Iface<IFACES0>::cast(d)->setOutputDevice(dev.index());
}

AudioOutput::AudioOutput(Phonon::Category category, QObject *parent)
    : AbstractAudioOutput(*new AudioOutputPrivate, parent)
{
    K_D(AudioOutput);
    d->init(category);
}

AudioOutput::AudioOutput(QObject *parent)
    : AbstractAudioOutput(*new AudioOutputPrivate, parent)
{
    K_D(AudioOutput);
    d->init(NoCategory);
}

void AudioOutputPrivate::init(Phonon::Category c)
{
    Q_Q(AudioOutput);
#ifndef QT_NO_DBUS
    adaptor = new AudioOutputAdaptor(q);
    static unsigned int number = 0;
    const QString &path = QLatin1String("/AudioOutputs/") + QString::number(number++);
    QDBusConnection con = QDBusConnection::sessionBus();
    con.registerObject(path, q);
    emit adaptor->newOutputAvailable(con.baseService(), path);
    q->connect(q, SIGNAL(volumeChanged(qreal)), adaptor, SIGNAL(volumeChanged(qreal)));
    q->connect(q, SIGNAL(mutedChanged(bool)), adaptor, SIGNAL(mutedChanged(bool)));
#endif

    category = c;

    // select hardware device according to the category
    device = AudioOutputDevice::fromIndex(GlobalConfig().audioOutputDeviceFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices));

    createBackendObject();

    q->connect(Factory::sender(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(_k_deviceListChanged()));
}

void AudioOutputPrivate::createBackendObject()
{
    if (m_backendObject)
        return;
    Q_Q(AudioOutput);
    m_backendObject = Factory::createAudioOutput(q);
    if (m_backendObject) {
        setupBackendObject();
    }
}

QString AudioOutput::name() const
{
    K_D(const AudioOutput);
    return d->name;
}

void AudioOutput::setName(const QString &newName)
{
    K_D(AudioOutput);
    if (d->name == newName) {
        return;
    }
    d->name = newName;
    setVolume(Platform::loadVolume(newName));
#ifndef QT_NO_DBUS
    emit d->adaptor->nameChanged(newName);
#endif
}

static const qreal LOUDNESS_TO_VOLTAGE_EXPONENT = qreal(0.67);
static const qreal VOLTAGE_TO_LOUDNESS_EXPONENT = qreal(1.0/LOUDNESS_TO_VOLTAGE_EXPONENT);

void AudioOutput::setVolume(qreal volume)
{
    K_D(AudioOutput);
    d->volume = volume;
    if (k_ptr->backendObject() && !d->muted) {
        // using Stevens' power law loudness is proportional to (sound pressure)^0.67
        // sound pressure is proportional to voltage:
        // p² \prop P \prop V²
        // => if a factor for loudness of x is requested
        INTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
    } else {
        emit volumeChanged(volume);
    }
    Platform::saveVolume(d->name, volume);
}

qreal AudioOutput::volume() const
{
    K_D(const AudioOutput);
    if (d->muted || !d->m_backendObject) {
        return d->volume;
    }
    return pow(INTERFACE_CALL(volume()), LOUDNESS_TO_VOLTAGE_EXPONENT);
}

#ifndef PHONON_LOG10OVER20
#define PHONON_LOG10OVER20
static const qreal log10over20 = qreal(0.1151292546497022842); // ln(10) / 20
#endif // PHONON_LOG10OVER20

qreal AudioOutput::volumeDecibel() const
{
    K_D(const AudioOutput);
    if (d->muted || !d->m_backendObject) {
        return log(d->volume) / log10over20;
    }
    return 0.67 * log(INTERFACE_CALL(volume())) / log10over20;
}

void AudioOutput::setVolumeDecibel(qreal newVolumeDecibel)
{
    setVolume(exp(newVolumeDecibel * log10over20));
}

bool AudioOutput::isMuted() const
{
    K_D(const AudioOutput);
    return d->muted;
}

void AudioOutput::setMuted(bool mute)
{
    K_D(AudioOutput);
    if (d->muted != mute) {
        if (mute) {
            d->muted = mute;
            if (k_ptr->backendObject()) {
                INTERFACE_CALL(setVolume(0.0));
            }
        } else {
            if (k_ptr->backendObject()) {
                INTERFACE_CALL(setVolume(pow(d->volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
            }
            d->muted = mute;
        }
        emit mutedChanged(mute);
    }
}

Category AudioOutput::category() const
{
    K_D(const AudioOutput);
    return d->category;
}

AudioOutputDevice AudioOutput::outputDevice() const
{
    K_D(const AudioOutput);
    return d->device;
}

bool AudioOutput::setOutputDevice(const AudioOutputDevice &newAudioOutputDevice)
{
    K_D(AudioOutput);
    if (!newAudioOutputDevice.isValid()) {
        d->outputDeviceOverridden = false;
        const int newIndex = GlobalConfig().audioOutputDeviceFor(d->category);
        if (newIndex == d->device.index()) {
            return true;
        }
        d->device = AudioOutputDevice::fromIndex(newIndex);
    } else {
        d->outputDeviceOverridden = true;
        if (d->device == newAudioOutputDevice) {
            return true;
        }
        d->device = newAudioOutputDevice;
    }
    if (k_ptr->backendObject()) {
        return callSetOutputDevice(k_ptr, d->device.index());
    }
    return true;
}

bool AudioOutputPrivate::aboutToDeleteBackendObject()
{
    if (m_backendObject) {
        volume = pINTERFACE_CALL(volume());
    }
    return AbstractAudioOutputPrivate::aboutToDeleteBackendObject();
}

void AudioOutputPrivate::setupBackendObject()
{
    Q_Q(AudioOutput);
    Q_ASSERT(m_backendObject);
    AbstractAudioOutputPrivate::setupBackendObject();

    QObject::connect(m_backendObject, SIGNAL(volumeChanged(qreal)), q, SLOT(_k_volumeChanged(qreal)));
    QObject::connect(m_backendObject, SIGNAL(audioDeviceFailed()), q, SLOT(_k_audioDeviceFailed()));

    // set up attributes
    pINTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));

    // if the output device is not available and the device was not explicitly set
    if (!callSetOutputDevice(this, device) && !outputDeviceOverridden) {
        // fall back in the preference list of output devices
        QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
        if (deviceList.isEmpty()) {
            return;
        }
        foreach (int devIndex, deviceList) {
            const AudioOutputDevice &dev = AudioOutputDevice::fromIndex(devIndex);
            if (callSetOutputDevice(this, dev)) {
                handleAutomaticDeviceChange(dev, AudioOutputPrivate::FallbackChange);
                return; // found one that works
            }
        }
        // if we get here there is no working output device. Tell the backend.
        const AudioOutputDevice none;
        callSetOutputDevice(this, none);
        handleAutomaticDeviceChange(none, FallbackChange);
    }
}

void AudioOutputPrivate::_k_volumeChanged(qreal newVolume)
{
    if (!muted) {
        Q_Q(AudioOutput);
        emit q->volumeChanged(pow(newVolume, qreal(0.67)));
    }
}

void AudioOutputPrivate::_k_revertFallback()
{
    if (deviceBeforeFallback == -1) {
        return;
    }
    device = AudioOutputDevice::fromIndex(deviceBeforeFallback);
    callSetOutputDevice(this, device);
    Q_Q(AudioOutput);
    emit q->outputDeviceChanged(device);
#ifndef QT_NO_DBUS
    emit adaptor->outputDeviceIndexChanged(device.index());
#endif
}

void AudioOutputPrivate::_k_audioDeviceFailed()
{
    pDebug() << Q_FUNC_INFO;
    // outputDeviceIndex identifies a failing device
    // fall back in the preference list of output devices
    QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
    foreach (int devIndex, deviceList) {
        // if it's the same device as the one that failed, ignore it
        if (device.index() != devIndex) {
            const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
            if (callSetOutputDevice(this, info)) {
                handleAutomaticDeviceChange(info, FallbackChange);
                return; // found one that works
            }
        }
    }
    // if we get here there is no working output device. Tell the backend.
    const AudioOutputDevice none;
    callSetOutputDevice(this, none);
    handleAutomaticDeviceChange(none, FallbackChange);
}

void AudioOutputPrivate::_k_deviceListChanged()
{
    pDebug() << Q_FUNC_INFO;
    // let's see if there's a usable device higher in the preference list
    QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings);
    DeviceChangeType changeType = HigherPreferenceChange;
    foreach (int devIndex, deviceList) {
        const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
        if (!info.property("available").toBool()) {
            if (device.index() == devIndex) {
                // we've reached the currently used device and it's not available anymore, so we
                // fallback to the next available device
                changeType = FallbackChange;
            }
            pDebug() << devIndex << "is not available";
            continue;
        }
        pDebug() << devIndex << "is available";
        if (device.index() == devIndex) {
            // we've reached the currently used device, nothing to change
            break;
        }
        if (callSetOutputDevice(this, info)) {
            handleAutomaticDeviceChange(info, changeType);
            break; // found one with higher preference that works
        }
    }
}

static struct
{
    int first;
    int second;
} g_lastFallback = { 0, 0 };

void AudioOutputPrivate::handleAutomaticDeviceChange(const AudioOutputDevice &device2, DeviceChangeType type)
{
    Q_Q(AudioOutput);
    deviceBeforeFallback = device.index();
    device = device2;
    emit q->outputDeviceChanged(device2);
#ifndef QT_NO_DBUS
    emit adaptor->outputDeviceIndexChanged(device.index());
#endif
    const AudioOutputDevice &device1 = AudioOutputDevice::fromIndex(deviceBeforeFallback);
    switch (type) {
    case FallbackChange:
        if (g_lastFallback.first != device1.index() || g_lastFallback.second != device2.index()) {
#ifndef QT_NO_PHONON_PLATFORMPLUGIN
            const QString &text = //device2.isValid() ?
                AudioOutput::tr("The audio playback device %1 does not work.
"
                        "Falling back to %2.").arg(device1.name()).arg(device2.name()) /*:
                AudioOutput::tr("The audio playback device %1 does not work.
"
                        "No other device available.").arg(device1.name())*/;
            Platform::notification("AudioDeviceFallback", text);
#endif //QT_NO_PHONON_PLATFORMPLUGIN
            g_lastFallback.first = device1.index();
            g_lastFallback.second = device2.index();
        }
        break;
    case HigherPreferenceChange:
        {
#ifndef QT_NO_PHONON_PLATFORMPLUGIN
        const QString text = AudioOutput::tr("Switching to the audio playback device %1
"
                "which just became available and has higher preference.").arg(device2.name());
        Platform::notification("AudioDeviceFallback", text,
                QStringList(AudioOutput::tr("Revert back to device '%1'").arg(device1.name())),
                q, SLOT(_k_revertFallback()));
#endif //QT_NO_PHONON_PLATFORMPLUGIN
        g_lastFallback.first = 0;
        g_lastFallback.second = 0;
        }
        break;
    }
}

AudioOutputPrivate::~AudioOutputPrivate()
{
#ifndef QT_NO_DBUS
    emit adaptor->outputDestroyed();
#endif
}

} //namespace Phonon

QT_END_NAMESPACE

#include "moc_audiooutput.cpp"

#undef PHONON_CLASSNAME
#undef PHONON_INTERFACENAME
#undef IFACES2
#undef IFACES1
#undef IFACES0
<commit_msg>forwardport: two more adaptor accesses where adaptor might be 0<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Trolltech ASA
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.

*/
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "factory_p.h"
#include "objectdescription.h"
#include "audiooutputadaptor_p.h"
#include "globalconfig_p.h"
#include "audiooutputinterface.h"
#include "phononnamespace_p.h"
#include "platform_p.h"

#include <qmath.h>

#define PHONON_CLASSNAME AudioOutput
#define IFACES2 AudioOutputInterface42
#define IFACES1 IFACES2
#define IFACES0 AudioOutputInterface40, IFACES1
#define PHONON_INTERFACENAME IFACES0

QT_BEGIN_NAMESPACE

namespace Phonon
{

static inline bool callSetOutputDevice(MediaNodePrivate *const d, int index)
{
    Iface<IFACES2> iface(d);
    if (iface) {
        return iface->setOutputDevice(AudioOutputDevice::fromIndex(index));
    }
    return Iface<IFACES0>::cast(d)->setOutputDevice(index);
}

static inline bool callSetOutputDevice(MediaNodePrivate *const d, const AudioOutputDevice &dev)
{
    Iface<IFACES2> iface(d);
    if (iface) {
        return iface->setOutputDevice(dev);
    }
    return Iface<IFACES0>::cast(d)->setOutputDevice(dev.index());
}

AudioOutput::AudioOutput(Phonon::Category category, QObject *parent)
    : AbstractAudioOutput(*new AudioOutputPrivate, parent)
{
    K_D(AudioOutput);
    d->init(category);
}

AudioOutput::AudioOutput(QObject *parent)
    : AbstractAudioOutput(*new AudioOutputPrivate, parent)
{
    K_D(AudioOutput);
    d->init(NoCategory);
}

void AudioOutputPrivate::init(Phonon::Category c)
{
    Q_Q(AudioOutput);
#ifndef QT_NO_DBUS
    adaptor = new AudioOutputAdaptor(q);
    static unsigned int number = 0;
    const QString &path = QLatin1String("/AudioOutputs/") + QString::number(number++);
    QDBusConnection con = QDBusConnection::sessionBus();
    con.registerObject(path, q);
    emit adaptor->newOutputAvailable(con.baseService(), path);
    q->connect(q, SIGNAL(volumeChanged(qreal)), adaptor, SIGNAL(volumeChanged(qreal)));
    q->connect(q, SIGNAL(mutedChanged(bool)), adaptor, SIGNAL(mutedChanged(bool)));
#endif

    category = c;

    // select hardware device according to the category
    device = AudioOutputDevice::fromIndex(GlobalConfig().audioOutputDeviceFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices));

    createBackendObject();

    q->connect(Factory::sender(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(_k_deviceListChanged()));
}

void AudioOutputPrivate::createBackendObject()
{
    if (m_backendObject)
        return;
    Q_Q(AudioOutput);
    m_backendObject = Factory::createAudioOutput(q);
    if (m_backendObject) {
        setupBackendObject();
    }
}

QString AudioOutput::name() const
{
    K_D(const AudioOutput);
    return d->name;
}

void AudioOutput::setName(const QString &newName)
{
    K_D(AudioOutput);
    if (d->name == newName) {
        return;
    }
    d->name = newName;
    setVolume(Platform::loadVolume(newName));
#ifndef QT_NO_DBUS
    if (d->adaptor) {
        emit d->adaptor->nameChanged(newName);
    }
#endif
}

static const qreal LOUDNESS_TO_VOLTAGE_EXPONENT = qreal(0.67);
static const qreal VOLTAGE_TO_LOUDNESS_EXPONENT = qreal(1.0/LOUDNESS_TO_VOLTAGE_EXPONENT);

void AudioOutput::setVolume(qreal volume)
{
    K_D(AudioOutput);
    d->volume = volume;
    if (k_ptr->backendObject() && !d->muted) {
        // using Stevens' power law loudness is proportional to (sound pressure)^0.67
        // sound pressure is proportional to voltage:
        // p² \prop P \prop V²
        // => if a factor for loudness of x is requested
        INTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
    } else {
        emit volumeChanged(volume);
    }
    Platform::saveVolume(d->name, volume);
}

qreal AudioOutput::volume() const
{
    K_D(const AudioOutput);
    if (d->muted || !d->m_backendObject) {
        return d->volume;
    }
    return pow(INTERFACE_CALL(volume()), LOUDNESS_TO_VOLTAGE_EXPONENT);
}

#ifndef PHONON_LOG10OVER20
#define PHONON_LOG10OVER20
static const qreal log10over20 = qreal(0.1151292546497022842); // ln(10) / 20
#endif // PHONON_LOG10OVER20

qreal AudioOutput::volumeDecibel() const
{
    K_D(const AudioOutput);
    if (d->muted || !d->m_backendObject) {
        return log(d->volume) / log10over20;
    }
    return 0.67 * log(INTERFACE_CALL(volume())) / log10over20;
}

void AudioOutput::setVolumeDecibel(qreal newVolumeDecibel)
{
    setVolume(exp(newVolumeDecibel * log10over20));
}

bool AudioOutput::isMuted() const
{
    K_D(const AudioOutput);
    return d->muted;
}

void AudioOutput::setMuted(bool mute)
{
    K_D(AudioOutput);
    if (d->muted != mute) {
        if (mute) {
            d->muted = mute;
            if (k_ptr->backendObject()) {
                INTERFACE_CALL(setVolume(0.0));
            }
        } else {
            if (k_ptr->backendObject()) {
                INTERFACE_CALL(setVolume(pow(d->volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
            }
            d->muted = mute;
        }
        emit mutedChanged(mute);
    }
}

Category AudioOutput::category() const
{
    K_D(const AudioOutput);
    return d->category;
}

AudioOutputDevice AudioOutput::outputDevice() const
{
    K_D(const AudioOutput);
    return d->device;
}

bool AudioOutput::setOutputDevice(const AudioOutputDevice &newAudioOutputDevice)
{
    K_D(AudioOutput);
    if (!newAudioOutputDevice.isValid()) {
        d->outputDeviceOverridden = false;
        const int newIndex = GlobalConfig().audioOutputDeviceFor(d->category);
        if (newIndex == d->device.index()) {
            return true;
        }
        d->device = AudioOutputDevice::fromIndex(newIndex);
    } else {
        d->outputDeviceOverridden = true;
        if (d->device == newAudioOutputDevice) {
            return true;
        }
        d->device = newAudioOutputDevice;
    }
    if (k_ptr->backendObject()) {
        return callSetOutputDevice(k_ptr, d->device.index());
    }
    return true;
}

bool AudioOutputPrivate::aboutToDeleteBackendObject()
{
    if (m_backendObject) {
        volume = pINTERFACE_CALL(volume());
    }
    return AbstractAudioOutputPrivate::aboutToDeleteBackendObject();
}

void AudioOutputPrivate::setupBackendObject()
{
    Q_Q(AudioOutput);
    Q_ASSERT(m_backendObject);
    AbstractAudioOutputPrivate::setupBackendObject();

    QObject::connect(m_backendObject, SIGNAL(volumeChanged(qreal)), q, SLOT(_k_volumeChanged(qreal)));
    QObject::connect(m_backendObject, SIGNAL(audioDeviceFailed()), q, SLOT(_k_audioDeviceFailed()));

    // set up attributes
    pINTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));

    // if the output device is not available and the device was not explicitly set
    if (!callSetOutputDevice(this, device) && !outputDeviceOverridden) {
        // fall back in the preference list of output devices
        QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
        if (deviceList.isEmpty()) {
            return;
        }
        foreach (int devIndex, deviceList) {
            const AudioOutputDevice &dev = AudioOutputDevice::fromIndex(devIndex);
            if (callSetOutputDevice(this, dev)) {
                handleAutomaticDeviceChange(dev, AudioOutputPrivate::FallbackChange);
                return; // found one that works
            }
        }
        // if we get here there is no working output device. Tell the backend.
        const AudioOutputDevice none;
        callSetOutputDevice(this, none);
        handleAutomaticDeviceChange(none, FallbackChange);
    }
}

void AudioOutputPrivate::_k_volumeChanged(qreal newVolume)
{
    if (!muted) {
        Q_Q(AudioOutput);
        emit q->volumeChanged(pow(newVolume, qreal(0.67)));
    }
}

void AudioOutputPrivate::_k_revertFallback()
{
    if (deviceBeforeFallback == -1) {
        return;
    }
    device = AudioOutputDevice::fromIndex(deviceBeforeFallback);
    callSetOutputDevice(this, device);
    Q_Q(AudioOutput);
    emit q->outputDeviceChanged(device);
#ifndef QT_NO_DBUS
    emit adaptor->outputDeviceIndexChanged(device.index());
#endif
}

void AudioOutputPrivate::_k_audioDeviceFailed()
{
    pDebug() << Q_FUNC_INFO;
    // outputDeviceIndex identifies a failing device
    // fall back in the preference list of output devices
    QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
    foreach (int devIndex, deviceList) {
        // if it's the same device as the one that failed, ignore it
        if (device.index() != devIndex) {
            const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
            if (callSetOutputDevice(this, info)) {
                handleAutomaticDeviceChange(info, FallbackChange);
                return; // found one that works
            }
        }
    }
    // if we get here there is no working output device. Tell the backend.
    const AudioOutputDevice none;
    callSetOutputDevice(this, none);
    handleAutomaticDeviceChange(none, FallbackChange);
}

void AudioOutputPrivate::_k_deviceListChanged()
{
    pDebug() << Q_FUNC_INFO;
    // let's see if there's a usable device higher in the preference list
    QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings);
    DeviceChangeType changeType = HigherPreferenceChange;
    foreach (int devIndex, deviceList) {
        const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
        if (!info.property("available").toBool()) {
            if (device.index() == devIndex) {
                // we've reached the currently used device and it's not available anymore, so we
                // fallback to the next available device
                changeType = FallbackChange;
            }
            pDebug() << devIndex << "is not available";
            continue;
        }
        pDebug() << devIndex << "is available";
        if (device.index() == devIndex) {
            // we've reached the currently used device, nothing to change
            break;
        }
        if (callSetOutputDevice(this, info)) {
            handleAutomaticDeviceChange(info, changeType);
            break; // found one with higher preference that works
        }
    }
}

static struct
{
    int first;
    int second;
} g_lastFallback = { 0, 0 };

void AudioOutputPrivate::handleAutomaticDeviceChange(const AudioOutputDevice &device2, DeviceChangeType type)
{
    Q_Q(AudioOutput);
    deviceBeforeFallback = device.index();
    device = device2;
    emit q->outputDeviceChanged(device2);
#ifndef QT_NO_DBUS
    emit adaptor->outputDeviceIndexChanged(device.index());
#endif
    const AudioOutputDevice &device1 = AudioOutputDevice::fromIndex(deviceBeforeFallback);
    switch (type) {
    case FallbackChange:
        if (g_lastFallback.first != device1.index() || g_lastFallback.second != device2.index()) {
#ifndef QT_NO_PHONON_PLATFORMPLUGIN
            const QString &text = //device2.isValid() ?
                AudioOutput::tr("The audio playback device %1 does not work.
"
                        "Falling back to %2.").arg(device1.name()).arg(device2.name()) /*:
                AudioOutput::tr("The audio playback device %1 does not work.
"
                        "No other device available.").arg(device1.name())*/;
            Platform::notification("AudioDeviceFallback", text);
#endif //QT_NO_PHONON_PLATFORMPLUGIN
            g_lastFallback.first = device1.index();
            g_lastFallback.second = device2.index();
        }
        break;
    case HigherPreferenceChange:
        {
#ifndef QT_NO_PHONON_PLATFORMPLUGIN
        const QString text = AudioOutput::tr("Switching to the audio playback device %1
"
                "which just became available and has higher preference.").arg(device2.name());
        Platform::notification("AudioDeviceFallback", text,
                QStringList(AudioOutput::tr("Revert back to device '%1'").arg(device1.name())),
                q, SLOT(_k_revertFallback()));
#endif //QT_NO_PHONON_PLATFORMPLUGIN
        g_lastFallback.first = 0;
        g_lastFallback.second = 0;
        }
        break;
    }
}

AudioOutputPrivate::~AudioOutputPrivate()
{
#ifndef QT_NO_DBUS
    if (adaptor) {
        emit adaptor->outputDestroyed();
    }
#endif
}

} //namespace Phonon

QT_END_NAMESPACE

#include "moc_audiooutput.cpp"

#undef PHONON_CLASSNAME
#undef PHONON_INTERFACENAME
#undef IFACES2
#undef IFACES1
#undef IFACES0
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Patrick Reynolds <piki@github.com>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.

#include "browser/linux/notification_presenter_linux.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
#include "content/public/browser/desktop_notification_delegate.h"
#include "content/public/common/platform_notification_data.h"
#include "common/application_info.h"
#include "dbus/dbus.h"
#include "third_party/skia/include/core/SkBitmap.h"

namespace brightray {

namespace {

static bool unity_has_result = false;
static bool unity_result = false;

static bool UnityIsRunning() {
  if (unity_has_result) {
    return unity_result;
  }

  struct DBusError err;
  struct DBusConnection* bus = NULL;

  dbus_error_init(&err);

  bus = dbus_bus_get(DBUS_BUS_SESSION, &err);
  if (dbus_error_is_set(&err)) {
    g_debug("Failed to get Session Bus reference");
    unity_result = false;
    dbus_error_free(&err);

    goto out;
  }

  unity_result = dbus_bus_name_has_owner(bus, "com.canonical.indicator.session", &err);

  if (dbus_error_is_set(&err)) {
    unity_result = false;
    dbus_error_free(&err);
  }

out:
  if (bus) dbus_connection_unref(bus);

  unity_has_result = true;
  return unity_result;
}

void log_and_clear_error(GError* error, const char* context) {
  LOG(ERROR) << context
             << ": domain=" << error->domain
             << " code=" << error->code
             << " message=\"" << error->message << '"';
  g_error_free(error);
}

content::DesktopNotificationDelegate* GetDelegateFromNotification(
    NotifyNotification* notification) {
  return static_cast<content::DesktopNotificationDelegate*>(
      g_object_get_data(G_OBJECT(notification), "delegate"));
}

}  // namespace

// static
NotificationPresenter* NotificationPresenter::Create() {
  if (!notify_is_initted()) {
    notify_init(GetApplicationName().c_str());
  }
  return new NotificationPresenterLinux;
}

NotificationPresenterLinux::NotificationPresenterLinux()
    : notifications_(nullptr) {
}

NotificationPresenterLinux::~NotificationPresenterLinux() {
  // unref any outstanding notifications, and then free the list.
  if (notifications_)
    g_list_free_full(notifications_, g_object_unref);
}

void NotificationPresenterLinux::ShowNotification(
    const content::PlatformNotificationData& data,
    const SkBitmap& icon,
    scoped_ptr<content::DesktopNotificationDelegate> delegate_ptr,
    base::Closure* cancel_callback) {
  std::string title = base::UTF16ToUTF8(data.title);
  std::string body = base::UTF16ToUTF8(data.body);
  NotifyNotification* notification = notify_notification_new(title.c_str(), body.c_str(), nullptr);

  content::DesktopNotificationDelegate* delegate = delegate_ptr.release();

  g_object_set_data_full(G_OBJECT(notification), "delegate", delegate, operator delete);
  g_signal_connect(notification, "closed", G_CALLBACK(OnNotificationClosedThunk), this);

  // NB: On Unity, adding a notification action will cause the notification
  // to display as a modal dialog box. Testing for distros that have "Unity
  // Zen Nature" is difficult, we will test for the presence of the indicate
  // dbus service
  if (!UnityIsRunning()) {
    notify_notification_add_action(
        notification, "default", "View", OnNotificationViewThunk, this, nullptr);
  }

  if (!icon.drawsNothing()) {
    GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(icon);
    notify_notification_set_image_from_pixbuf(notification, pixbuf);
    notify_notification_set_timeout(notification, NOTIFY_EXPIRES_DEFAULT);
    g_object_unref(pixbuf);
  }

  GError* error = nullptr;
  notify_notification_show(notification, &error);
  if (error) {
    log_and_clear_error(error, "notify_notification_show");
    g_object_unref(notification);
    return;
  }

  notifications_ = g_list_append(notifications_, notification);
  delegate->NotificationDisplayed();

  if (cancel_callback)
    *cancel_callback = base::Bind(
        &NotificationPresenterLinux::CancelNotification,
        base::Unretained(this),
        notification);
}

void NotificationPresenterLinux::CancelNotification(NotifyNotification* notification) {
  GError* error = nullptr;
  notify_notification_close(notification, &error);
  if (error)
    log_and_clear_error(error, "notify_notification_close");

  GetDelegateFromNotification(notification)->NotificationClosed();
  DeleteNotification(notification);
}

void NotificationPresenterLinux::DeleteNotification(NotifyNotification* notification) {
  notifications_ = g_list_remove(notifications_, notification);
  g_object_unref(notification);
}

void NotificationPresenterLinux::OnNotificationClosed(NotifyNotification* notification) {
  if (!notification)
    return;
  GetDelegateFromNotification(notification)->NotificationClosed();
  DeleteNotification(notification);
}

void NotificationPresenterLinux::OnNotificationView(
    NotifyNotification* notification, char* action) {
  if (!notification)
    return;
  GetDelegateFromNotification(notification)->NotificationClick();
  DeleteNotification(notification);
}

}  // namespace brightray
<commit_msg>Rewrite unity check to look for libunity SOs<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Patrick Reynolds <piki@github.com>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.

#include "browser/linux/notification_presenter_linux.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/files/file_enumerator.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
#include "content/public/browser/desktop_notification_delegate.h"
#include "content/public/common/platform_notification_data.h"
#include "common/application_info.h"
#include "third_party/skia/include/core/SkBitmap.h"

using namespace base;
using namespace std;

namespace brightray {

namespace {

static bool unity_has_result = false;
static bool unity_result = false;

static bool UnityIsRunning() {
  FileEnumerator* enumerator = NULL;

  if (unity_has_result) {
    return unity_result;
  }

  // Look for the presence of libunity as our hint that we're under Ubuntu
  FilePath haystack;
  string needle("/usr/lib/libunity-");

  enumerator = new FileEnumerator(FilePath("/usr/lib"), false, FileEnumerator::FILES);

  while (!((haystack = enumerator->Next()).empty())) {
    if (haystack.value().compare(0, needle.length(), needle) == 0) {
      unity_result = true;
      goto out;
    }
  }

  unity_result = false;

out:
  if (enumerator) delete enumerator;
  unity_has_result = true;
  return unity_result;
}

void log_and_clear_error(GError* error, const char* context) {
  LOG(ERROR) << context
             << ": domain=" << error->domain
             << " code=" << error->code
             << " message=\"" << error->message << '"';
  g_error_free(error);
}

content::DesktopNotificationDelegate* GetDelegateFromNotification(
    NotifyNotification* notification) {
  return static_cast<content::DesktopNotificationDelegate*>(
      g_object_get_data(G_OBJECT(notification), "delegate"));
}

}  // namespace

// static
NotificationPresenter* NotificationPresenter::Create() {
  if (!notify_is_initted()) {
    notify_init(GetApplicationName().c_str());
  }
  return new NotificationPresenterLinux;
}

NotificationPresenterLinux::NotificationPresenterLinux()
    : notifications_(nullptr) {
}

NotificationPresenterLinux::~NotificationPresenterLinux() {
  // unref any outstanding notifications, and then free the list.
  if (notifications_)
    g_list_free_full(notifications_, g_object_unref);
}

void NotificationPresenterLinux::ShowNotification(
    const content::PlatformNotificationData& data,
    const SkBitmap& icon,
    scoped_ptr<content::DesktopNotificationDelegate> delegate_ptr,
    base::Closure* cancel_callback) {
  std::string title = base::UTF16ToUTF8(data.title);
  std::string body = base::UTF16ToUTF8(data.body);
  NotifyNotification* notification = notify_notification_new(title.c_str(), body.c_str(), nullptr);

  content::DesktopNotificationDelegate* delegate = delegate_ptr.release();

  g_object_set_data_full(G_OBJECT(notification), "delegate", delegate, operator delete);
  g_signal_connect(notification, "closed", G_CALLBACK(OnNotificationClosedThunk), this);

  // NB: On Unity, adding a notification action will cause the notification
  // to display as a modal dialog box. Testing for distros that have "Unity
  // Zen Nature" is difficult, we will test for the presence of the indicate
  // dbus service
  if (!UnityIsRunning()) {
    notify_notification_add_action(
        notification, "default", "View", OnNotificationViewThunk, this, nullptr);
  }

  if (!icon.drawsNothing()) {
    GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(icon);
    notify_notification_set_image_from_pixbuf(notification, pixbuf);
    notify_notification_set_timeout(notification, NOTIFY_EXPIRES_DEFAULT);
    g_object_unref(pixbuf);
  }

  GError* error = nullptr;
  notify_notification_show(notification, &error);
  if (error) {
    log_and_clear_error(error, "notify_notification_show");
    g_object_unref(notification);
    return;
  }

  notifications_ = g_list_append(notifications_, notification);
  delegate->NotificationDisplayed();

  if (cancel_callback)
    *cancel_callback = base::Bind(
        &NotificationPresenterLinux::CancelNotification,
        base::Unretained(this),
        notification);
}

void NotificationPresenterLinux::CancelNotification(NotifyNotification* notification) {
  GError* error = nullptr;
  notify_notification_close(notification, &error);
  if (error)
    log_and_clear_error(error, "notify_notification_close");

  GetDelegateFromNotification(notification)->NotificationClosed();
  DeleteNotification(notification);
}

void NotificationPresenterLinux::DeleteNotification(NotifyNotification* notification) {
  notifications_ = g_list_remove(notifications_, notification);
  g_object_unref(notification);
}

void NotificationPresenterLinux::OnNotificationClosed(NotifyNotification* notification) {
  if (!notification)
    return;
  GetDelegateFromNotification(notification)->NotificationClosed();
  DeleteNotification(notification);
}

void NotificationPresenterLinux::OnNotificationView(
    NotifyNotification* notification, char* action) {
  if (!notification)
    return;
  GetDelegateFromNotification(notification)->NotificationClick();
  DeleteNotification(notification);
}

}  // namespace brightray
<|endoftext|>


<commit_before>
#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>

#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>

#include <stdio.h>
#include <tiffio.h>

/****************************************************************************
 *
 * Follows is code extracted from the simage library.  Original Authors:
 *
 *      Systems in Motion,
 *      <URL:http://www.sim.no>
 *
 *      Peder Blekken <pederb@sim.no>
 *      Morten Eriksen <mortene@sim.no>
 *      Marius Bugge Monsen <mariusbu@sim.no>
 *
 * The original COPYING notice
 *
 *      All files in this library are public domain, except simage_rgb.cpp which is
 *      Copyright (c) Mark J Kilgard <mjk@nvidia.com>. I will contact Mark
 *      very soon to hear if this source also can become public domain.
 *
 *      Please send patches for bugs and new features to: <pederb@sim.no>.
 *
 *      Peder Blekken
 *
 *
 * Ported into the OSG as a plugin, Robert Osfield Decemeber 2000.
 * Note, reference above to license of simage_rgb is not relevent to the OSG
 * as the OSG does not use it.  Also for patches, bugs and new features
 * please send them direct to the OSG dev team rather than address above.
 *
 **********************************************************************/

#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <stdlib.h>

#define ERR_NO_ERROR    0
#define ERR_OPEN        1
#define ERR_READ        2
#define ERR_MEM         3
#define ERR_UNSUPPORTED 4
#define ERR_TIFFLIB     5

static int tifferror = ERR_NO_ERROR;

int
simage_tiff_error(char * buffer, int buflen)
{
    switch (tifferror)
    {
        case ERR_OPEN:
            strncpy(buffer, "TIFF loader: Error opening file", buflen);
            break;
        case ERR_MEM:
            strncpy(buffer, "TIFF loader: Out of memory error", buflen);
            break;
        case ERR_UNSUPPORTED:
            strncpy(buffer, "TIFF loader: Unsupported image type", buflen);
            break;
        case ERR_TIFFLIB:
            strncpy(buffer, "TIFF loader: Illegal tiff file", buflen);
            break;
    }
    return tifferror;
}

static void
tiff_error(const char*, const char*, va_list)
{
    // values are (const char* module, const char* fmt, va_list list)
    /* FIXME: store error message ? */
}

static void
tiff_warn(const char *, const char *, va_list)
{
    // values are (const char* module, const char* fmt, va_list list)
    /* FIXME: notify? */
}

static int
checkcmap(int n, uint16* r, uint16* g, uint16* b)
{
    while (n-- > 0)
        if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
            return (16);
    /* Assuming 8-bit colormap */
    return (8);
}

static void
invert_row(unsigned char *ptr, unsigned char *data, int n, int invert, uint16 bitspersample)
{
    if (bitspersample == 8)
    {
        while (n--)
        {
            if (invert) *ptr++ = 255 - *data++;
            else *ptr++ = *data++;
        }
    }
    else
    {
        unsigned short *ptr1 = (unsigned short *)ptr;
        unsigned short *data1 = (unsigned short *)data;

        while (n--)
        {
            if (invert) *ptr1++ = 65535 - *data1++;
            else *ptr1++ = *data1++;
        }
    }
}

static void
remap_row(unsigned char *ptr, unsigned char *data, int n,
unsigned short *rmap, unsigned short *gmap, unsigned short *bmap)
{
    unsigned int ix;
    while (n--)
    {
        ix = *data++;
        *ptr++ = (unsigned char) rmap[ix];
        *ptr++ = (unsigned char) gmap[ix];
        *ptr++ = (unsigned char) bmap[ix];
    }
}

static void
copy_row(unsigned char *ptr, unsigned char *data, int n, int numSamples)
{
    while (n--)
    {
        for(int i=0;i<numSamples;++i)
        {
            *ptr++ = *data++;
        }
    }
}

static void
interleave_row(unsigned char *ptr,
unsigned char *red, unsigned char *blue, unsigned char *green,
int n)
{
    while (n--)
    {
        *ptr++ = *red++;
        *ptr++ = *green++;
        *ptr++ = *blue++;
    }
}

int
simage_tiff_identify(const char *,
const unsigned char *header,
int headerlen)
{
    static unsigned char tifcmp[] = {0x4d, 0x4d, 0x0, 0x2a};
    static unsigned char tifcmp2[] = {0x49, 0x49, 0x2a, 0};

    if (headerlen < 4) return 0;
    if (memcmp((const void*)header, (const void*)tifcmp, 4) == 0) return 1;
    if (memcmp((const void*)header, (const void*)tifcmp2, 4) == 0) return 1;
    return 0;
}

/* useful defines (undef'ed below) */
#define CVT(x)      (((x) * 255L) / ((1L<<16)-1))
#define pack(a,b)   ((a)<<8 | (b))

unsigned char *
simage_tiff_load(const char *filename,
int *width_ret,
int *height_ret,
int *numComponents_ret)
{
    TIFF *in;
    uint16 samplesperpixel;
    uint16 bitspersample;
    uint16 photometric;
    uint32 w, h;
    uint16 config;
    uint16* red;
    uint16* green;
    uint16* blue;
    unsigned char *inbuf = NULL;
    tsize_t rowsize;
    uint32 row;
    int format;
    unsigned char *buffer;
    int width;
    int height;
    unsigned char *currPtr;

    TIFFSetErrorHandler(tiff_error);
    TIFFSetWarningHandler(tiff_warn);

    in = TIFFOpen(filename, "r");
    if (in == NULL)
    {
        tifferror = ERR_OPEN;
        return NULL;
    }
    if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) == 1)
    {
        if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE &&
            photometric != PHOTOMETRIC_MINISWHITE &&
            photometric != PHOTOMETRIC_MINISBLACK)
        {
            /*Bad photometric; can only handle Grayscale, RGB and Palette images :-( */
            TIFFClose(in);
            tifferror = ERR_UNSUPPORTED;
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }

    if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel) == 1)
    {
        if (samplesperpixel != 1 &&
            samplesperpixel != 2 &&
            samplesperpixel != 3 &&
            samplesperpixel != 4)
        {
            /* Bad samples/pixel */
            tifferror = ERR_UNSUPPORTED;
            TIFFClose(in);
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }

    if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample) == 1)
    {
         if (bitspersample != 8 && bitspersample != 16)
        {
            /* can only handle 8 and 16 bit samples. */
            TIFFClose(in);
            tifferror = ERR_UNSUPPORTED;
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }

    if (TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w) != 1 ||
        TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h) != 1 ||
        TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config) != 1)
    {
        TIFFClose(in);
        tifferror = ERR_READ;
        return NULL;
    }

    /*
    if (photometric == PHOTOMETRIC_MINISWHITE ||
        photometric == PHOTOMETRIC_MINISBLACK)
        format = 1;
    else
        format = 3;
    */
    format = samplesperpixel * bitspersample / 8;

    buffer = new unsigned char [w*h*format];
    for(unsigned char* ptr=buffer;ptr<buffer+w*h*format;++ptr) *ptr = 0;

    if (!buffer)
    {
        tifferror = ERR_MEM;
        TIFFClose(in);
        return NULL;
    }

    width = w;
    height = h;

    currPtr = buffer + (h-1)*w*format;

    tifferror = ERR_NO_ERROR;

    switch (pack(photometric, config))
    {
        case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_SEPARATE):
        case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_SEPARATE):
            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                invert_row(currPtr, inbuf, w, photometric == PHOTOMETRIC_MINISWHITE, bitspersample);
                //invert_row(currPtr, inbuf, w, photometric == PHOTOMETRIC_MINISWHITE);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
            if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue) != 1)
                tifferror = ERR_READ;
            /* */
            /* Convert 16-bit colormap to 8-bit (unless it looks */
            /* like an old-style 8-bit colormap). */
            /* */
            if (!tifferror && checkcmap(1<<bitspersample, red, green, blue) == 16)
            {
                int i;
                for (i = (1<<bitspersample)-1; i >= 0; i--)
                {
                    red[i] = CVT(red[i]);
                    green[i] = CVT(green[i]);
                    blue[i] = CVT(blue[i]);
                }
            }

            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                remap_row(currPtr, inbuf, w, red, green, blue);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                copy_row(currPtr, inbuf, w,samplesperpixel);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE):
            osg::notify(osg::NOTICE)<<"case 4"<<std::endl;
            rowsize = TIFFScanlineSize(in);
            inbuf = new unsigned char [format*rowsize];
            for (row = 0; !tifferror && row < h; row++)
            {
                int s;
                for (s = 0; s < format; s++)
                {
                    if (TIFFReadScanline(in, (tdata_t)(inbuf+s*rowsize), (uint32)row, (tsample_t)s) < 0)
                    {
                        tifferror = ERR_READ; break;
                    }
                }
                if (!tifferror)
                {
                    interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, w);
                    currPtr -= format*w;
                }
            }
            break;
        default:
            tifferror = ERR_UNSUPPORTED;
            break;
    }

    if (inbuf) delete [] inbuf;
    TIFFClose(in);

    if (tifferror)
    {
        if (buffer) delete [] buffer;
        return NULL;
    }
    *width_ret = width;
    *height_ret = height;
    *numComponents_ret = format;
    return buffer;
}

#undef CVT
#undef pack

class ReaderWriterTIFF : public osgDB::ReaderWriter
{
    public:
        virtual const char* className() const { return "TIFF Image Reader"; }
        virtual bool acceptsExtension(const std::string& extension) const
        {
            if( osgDB::equalCaseInsensitive(extension,"tiff")) return true;
            if( osgDB::equalCaseInsensitive(extension,"tif") ) return true;
            return false;
        }

        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
        {
            std::string ext = osgDB::getLowerCaseFileExtension(file);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::string fileName = osgDB::findDataFile( file, options );
            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

            unsigned char *imageData = NULL;
            int width_ret;
            int height_ret;
            int numComponents_ret;

            imageData = simage_tiff_load(fileName.c_str(),&width_ret,&height_ret,&numComponents_ret);

            if (imageData==NULL)
            {
                char err_msg[256];
                simage_tiff_error( err_msg, sizeof(err_msg));
                osg::notify(osg::WARN) << err_msg << std::endl;
                return ReadResult::FILE_NOT_HANDLED;
            }

            int s = width_ret;
            int t = height_ret;
            int r = 1;

            int internalFormat = numComponents_ret;

            unsigned int pixelFormat =
                numComponents_ret == 1 ? GL_LUMINANCE :
            numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
            numComponents_ret == 3 ? GL_RGB :
            numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;

            unsigned int dataType = GL_UNSIGNED_BYTE;

            osg::Image* pOsgImage = new osg::Image;
            pOsgImage->setFileName(fileName.c_str());
            pOsgImage->setImage(s,t,r,
                internalFormat,
                pixelFormat,
                dataType,
                imageData,
                osg::Image::USE_NEW_DELETE);

            return pOsgImage;

        }
};

// now register with Registry to instantiate the above
// reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterTIFF> g_readerWriter_TIFF_Proxy;
<commit_msg>Fixed TIFF readers handling of interleaved data<commit_after>
#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>

#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>

#include <stdio.h>
#include <tiffio.h>

/****************************************************************************
 *
 * Follows is code extracted from the simage library.  Original Authors:
 *
 *      Systems in Motion,
 *      <URL:http://www.sim.no>
 *
 *      Peder Blekken <pederb@sim.no>
 *      Morten Eriksen <mortene@sim.no>
 *      Marius Bugge Monsen <mariusbu@sim.no>
 *
 * The original COPYING notice
 *
 *      All files in this library are public domain, except simage_rgb.cpp which is
 *      Copyright (c) Mark J Kilgard <mjk@nvidia.com>. I will contact Mark
 *      very soon to hear if this source also can become public domain.
 *
 *      Please send patches for bugs and new features to: <pederb@sim.no>.
 *
 *      Peder Blekken
 *
 *
 * Ported into the OSG as a plugin, Robert Osfield Decemeber 2000.
 * Note, reference above to license of simage_rgb is not relevent to the OSG
 * as the OSG does not use it.  Also for patches, bugs and new features
 * please send them direct to the OSG dev team rather than address above.
 *
 **********************************************************************/

#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <stdlib.h>

#define ERR_NO_ERROR    0
#define ERR_OPEN        1
#define ERR_READ        2
#define ERR_MEM         3
#define ERR_UNSUPPORTED 4
#define ERR_TIFFLIB     5

static int tifferror = ERR_NO_ERROR;

int
simage_tiff_error(char * buffer, int buflen)
{
    switch (tifferror)
    {
        case ERR_OPEN:
            strncpy(buffer, "TIFF loader: Error opening file", buflen);
            break;
        case ERR_MEM:
            strncpy(buffer, "TIFF loader: Out of memory error", buflen);
            break;
        case ERR_UNSUPPORTED:
            strncpy(buffer, "TIFF loader: Unsupported image type", buflen);
            break;
        case ERR_TIFFLIB:
            strncpy(buffer, "TIFF loader: Illegal tiff file", buflen);
            break;
    }
    return tifferror;
}

static void
tiff_error(const char*, const char*, va_list)
{
    // values are (const char* module, const char* fmt, va_list list)
    /* FIXME: store error message ? */
}

static void
tiff_warn(const char *, const char *, va_list)
{
    // values are (const char* module, const char* fmt, va_list list)
    /* FIXME: notify? */
}

static int
checkcmap(int n, uint16* r, uint16* g, uint16* b)
{
    while (n-- > 0)
        if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
            return (16);
    /* Assuming 8-bit colormap */
    return (8);
}

static void
invert_row(unsigned char *ptr, unsigned char *data, int n, int invert, uint16 bitspersample)
{
    if (bitspersample == 8)
    {
        while (n--)
        {
            if (invert) *ptr++ = 255 - *data++;
            else *ptr++ = *data++;
        }
    }
    else
    {
        unsigned short *ptr1 = (unsigned short *)ptr;
        unsigned short *data1 = (unsigned short *)data;

        while (n--)
        {
            if (invert) *ptr1++ = 65535 - *data1++;
            else *ptr1++ = *data1++;
        }
    }
}

static void
remap_row(unsigned char *ptr, unsigned char *data, int n,
unsigned short *rmap, unsigned short *gmap, unsigned short *bmap)
{
    unsigned int ix;
    while (n--)
    {
        ix = *data++;
        *ptr++ = (unsigned char) rmap[ix];
        *ptr++ = (unsigned char) gmap[ix];
        *ptr++ = (unsigned char) bmap[ix];
    }
}

static void
copy_row(unsigned char *ptr, unsigned char *data, int n, int numSamples)
{
    while (n--)
    {
        for(int i=0;i<numSamples;++i)
        {
            *ptr++ = *data++;
        }
    }
}

static void interleave_row(unsigned char *ptr,
                           unsigned char *red, unsigned char *green, unsigned char *blue,
                           int n, int numSamples)
{
    while (n--)
    {
        *ptr++ = *red++;
        *ptr++ = *green++;
        *ptr++ = *blue++;
        if (numSamples==4) *ptr++ = 255;
    }
}

static void interleave_row(unsigned char *ptr,
                           unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *alpha,
                           int n, int numSamples)
{
    while (n--)
    {
        *ptr++ = *red++;
        *ptr++ = *green++;
        *ptr++ = *blue++;
        if (numSamples==4) *ptr++ = *alpha++;
    }
}

int
simage_tiff_identify(const char *,
const unsigned char *header,
int headerlen)
{
    static unsigned char tifcmp[] = {0x4d, 0x4d, 0x0, 0x2a};
    static unsigned char tifcmp2[] = {0x49, 0x49, 0x2a, 0};

    if (headerlen < 4) return 0;
    if (memcmp((const void*)header, (const void*)tifcmp, 4) == 0) return 1;
    if (memcmp((const void*)header, (const void*)tifcmp2, 4) == 0) return 1;
    return 0;
}

/* useful defines (undef'ed below) */
#define CVT(x)      (((x) * 255L) / ((1L<<16)-1))
#define pack(a,b)   ((a)<<8 | (b))

unsigned char *
simage_tiff_load(const char *filename,
int *width_ret,
int *height_ret,
int *numComponents_ret)
{
    TIFF *in;
    uint16 samplesperpixel;
    uint16 bitspersample;
    uint16 photometric;
    uint32 w, h;
    uint16 config;
    uint16* red;
    uint16* green;
    uint16* blue;
    unsigned char *inbuf = NULL;
    tsize_t rowsize;
    uint32 row;
    int format;
    unsigned char *buffer;
    int width;
    int height;
    unsigned char *currPtr;

    TIFFSetErrorHandler(tiff_error);
    TIFFSetWarningHandler(tiff_warn);

    in = TIFFOpen(filename, "r");
    if (in == NULL)
    {
        tifferror = ERR_OPEN;
        return NULL;
    }
    if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) == 1)
    {
        if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE &&
            photometric != PHOTOMETRIC_MINISWHITE &&
            photometric != PHOTOMETRIC_MINISBLACK)
        {
            /*Bad photometric; can only handle Grayscale, RGB and Palette images :-( */
            TIFFClose(in);
            tifferror = ERR_UNSUPPORTED;
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }

    if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel) == 1)
    {
        if (samplesperpixel != 1 &&
            samplesperpixel != 2 &&
            samplesperpixel != 3 &&
            samplesperpixel != 4)
        {
            /* Bad samples/pixel */
            tifferror = ERR_UNSUPPORTED;
            TIFFClose(in);
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }

    if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample) == 1)
    {
         if (bitspersample != 8 && bitspersample != 16)
        {
            /* can only handle 8 and 16 bit samples. */
            TIFFClose(in);
            tifferror = ERR_UNSUPPORTED;
            return NULL;
        }
    }
    else
    {
        tifferror = ERR_READ;
        TIFFClose(in);
        return NULL;
    }

    if (TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w) != 1 ||
        TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h) != 1 ||
        TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config) != 1)
    {
        TIFFClose(in);
        tifferror = ERR_READ;
        return NULL;
    }

    /*
    if (photometric == PHOTOMETRIC_MINISWHITE ||
        photometric == PHOTOMETRIC_MINISBLACK)
        format = 1;
    else
        format = 3;
    */
    format = samplesperpixel * bitspersample / 8;

    buffer = new unsigned char [w*h*format];
    for(unsigned char* ptr=buffer;ptr<buffer+w*h*format;++ptr) *ptr = 0;

    if (!buffer)
    {
        tifferror = ERR_MEM;
        TIFFClose(in);
        return NULL;
    }

    width = w;
    height = h;

    currPtr = buffer + (h-1)*w*format;

    tifferror = ERR_NO_ERROR;

    switch (pack(photometric, config))
    {
        case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_SEPARATE):
        case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_SEPARATE):
            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                invert_row(currPtr, inbuf, w, photometric == PHOTOMETRIC_MINISWHITE, bitspersample);
                //invert_row(currPtr, inbuf, w, photometric == PHOTOMETRIC_MINISWHITE);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
        case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
            if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue) != 1)
                tifferror = ERR_READ;
            /* */
            /* Convert 16-bit colormap to 8-bit (unless it looks */
            /* like an old-style 8-bit colormap). */
            /* */
            if (!tifferror && checkcmap(1<<bitspersample, red, green, blue) == 16)
            {
                int i;
                for (i = (1<<bitspersample)-1; i >= 0; i--)
                {
                    red[i] = CVT(red[i]);
                    green[i] = CVT(green[i]);
                    blue[i] = CVT(blue[i]);
                }
            }

            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                remap_row(currPtr, inbuf, w, red, green, blue);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
            inbuf = new unsigned char [TIFFScanlineSize(in)];
            for (row = 0; row < h; row++)
            {
                if (TIFFReadScanline(in, inbuf, row, 0) < 0)
                {
                    tifferror = ERR_READ;
                    break;
                }
                copy_row(currPtr, inbuf, w,samplesperpixel);
                currPtr -= format*w;
            }
            break;

        case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE):
            rowsize = TIFFScanlineSize(in);
            inbuf = new unsigned char [format*rowsize];
            for (row = 0; !tifferror && row < h; row++)
            {
                int s;
                for (s = 0; s < format; s++)
                {
                    if (TIFFReadScanline(in, (tdata_t)(inbuf+s*rowsize), (uint32)row, (tsample_t)s) < 0)
                    {
                        tifferror = ERR_READ; break;
                    }
                }
                if (!tifferror)
                {
                    if (format==3) interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, w, format);
                    else if (format==4) interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, inbuf+3*rowsize, w, format);
                    currPtr -= format*w;
                }
            }
            break;
        default:
            tifferror = ERR_UNSUPPORTED;
            break;
    }

    if (inbuf) delete [] inbuf;
    TIFFClose(in);

    if (tifferror)
    {
        if (buffer) delete [] buffer;
        return NULL;
    }
    *width_ret = width;
    *height_ret = height;
    *numComponents_ret = format;
    return buffer;
}

#undef CVT
#undef pack

class ReaderWriterTIFF : public osgDB::ReaderWriter
{
    public:
        virtual const char* className() const { return "TIFF Image Reader"; }
        virtual bool acceptsExtension(const std::string& extension) const
        {
            if( osgDB::equalCaseInsensitive(extension,"tiff")) return true;
            if( osgDB::equalCaseInsensitive(extension,"tif") ) return true;
            return false;
        }

        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
        {
            std::string ext = osgDB::getLowerCaseFileExtension(file);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::string fileName = osgDB::findDataFile( file, options );
            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

            unsigned char *imageData = NULL;
            int width_ret;
            int height_ret;
            int numComponents_ret;

            imageData = simage_tiff_load(fileName.c_str(),&width_ret,&height_ret,&numComponents_ret);

            if (imageData==NULL)
            {
                char err_msg[256];
                simage_tiff_error( err_msg, sizeof(err_msg));
                osg::notify(osg::WARN) << err_msg << std::endl;
                return ReadResult::FILE_NOT_HANDLED;
            }

            int s = width_ret;
            int t = height_ret;
            int r = 1;

            int internalFormat = numComponents_ret;

            unsigned int pixelFormat =
                numComponents_ret == 1 ? GL_LUMINANCE :
                numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
                numComponents_ret == 3 ? GL_RGB :
                numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;

            unsigned int dataType = GL_UNSIGNED_BYTE;

            osg::Image* pOsgImage = new osg::Image;
            pOsgImage->setFileName(fileName.c_str());
            pOsgImage->setImage(s,t,r,
                internalFormat,
                pixelFormat,
                dataType,
                imageData,
                osg::Image::USE_NEW_DELETE);

            return pOsgImage;

        }
};

// now register with Registry to instantiate the above
// reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterTIFF> g_readerWriter_TIFF_Proxy;
<|endoftext|>


<commit_before>#include "googledataresource.h"

#include "settings.h"
#include "settingsadaptor.h"

#include <QtDBus/QDBusConnection>
#include <kabc/addressee.h>
#include <kabc/phonenumber.h>
#include <kabc/key.h>
#include <kabc/errorhandler.h>
#include <qstring.h>
#include <KWindowSystem>
#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>
#include <KUrl>

extern "C" {
#include <gcalendar.h>
#include <gcontact.h>
#include <gcal_status.h>
}

/** FIXME: for some reason the 'retrieveItem' functions is not being called.
 * this makes the entries to lack its contents (name, email, etc).
 * I should investigate why and fix, for while this is a workaround:
 * I report the payload in the 'retrieveItems' function.
 */
#define ITEM_BUG_WTF

using namespace Akonadi;

GoogleDataResource::GoogleDataResource( const QString &id )
	: ResourceBase(id), dlgConf(0), authenticated(false)
{
	new SettingsAdaptor( Settings::self() );
	QDBusConnection::sessionBus().registerObject(
		QLatin1String( "/Settings" ), Settings::self(),
		QDBusConnection::ExportAdaptors );

	changeRecorder()->itemFetchScope().fetchFullPayload();

	if (!(gcal = gcal_new(GCONTACT)))
		exit(1);
	gcal_set_store_xml(gcal, 1);
}

GoogleDataResource::~GoogleDataResource()
{
	gcal_delete(gcal);
	gcal_cleanup_contacts(&all_contacts);
	if (dlgConf)
		delete dlgConf;
}

void GoogleDataResource::retrieveCollections()
{
	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	Collection c;
	c.setParent(Collection::root());
	c.setRemoteId("google-contacts");
	c.setName(name());

	QStringList mimeTypes;
	mimeTypes << "text/directory";
	c.setContentMimeTypes(mimeTypes);

	Collection::List list;
	list << c;
	collectionsRetrieved(list);

}

void GoogleDataResource::retrieveItems( const Akonadi::Collection &collection )
{
	Q_UNUSED( collection );

	Item::List items;
	int result;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	/* Downloading the contacts can be slow and it is blocking. Will
	 * it mess up with akonadi?
	 */
	if ((result = gcal_get_contacts(gcal, &all_contacts)))
		exit(1);

	/* Each google entry has a unique ID and edit_url */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		Item item(QLatin1String("text/directory"));
		gcal_contact_t contact = gcal_contact_element(&all_contacts, i);

#ifdef ITEM_BUG_WTF
		KABC::Addressee addressee;
		KABC::PhoneNumber number;
		QString temp;

		/* name */
		temp = gcal_contact_get_title(contact);
		addressee.setNameFromString(temp);
		/* email */
		temp = gcal_contact_get_email(contact);
		addressee.insertEmail(temp, true);
		/* TODO: telefone, address, etc */

		item.setPayload<KABC::Addressee>(addressee);

		/* remoteID: etag+edit_url */
		KUrl urlEtag(gcal_contact_get_url(contact));
		urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

#endif

		item.setRemoteId(urlEtag.url());

		items << item;
	}

	itemsRetrieved(items);
}

bool GoogleDataResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED( parts );
	const QString entry_id = item.remoteId();
	QString temp;
	Item newItem(item);
	gcal_contact_t contact;
	KABC::Addressee addressee;
	KABC::PhoneNumber number;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return false;
	}

	/*
	 * And another question, are the requests in the same sequence that
	 * I informed in 'retrieveItems'? For while, I try to locate the entry...
	 */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		contact = gcal_contact_element(&all_contacts, i);
		if (entry_id == gcal_contact_get_id(contact)) {
			/* name */
			temp = gcal_contact_get_title(contact);
			addressee.setNameFromString(temp);

			/* email */
			temp = gcal_contact_get_email(contact);
			addressee.insertEmail(temp, true);

			/* TODO: telefone, address, etc */

			/* remoteID: etag+edit_url */
			KUrl urlEtag(gcal_contact_get_url(contact));
			urlEtag.addQueryItem("etag",
					     gcal_contact_get_etag(contact));

			newItem.setPayload<KABC::Addressee>(addressee);
			newItem.setRemoteId(urlEtag.url());
                        itemRetrieved(newItem);
			return true;
		}

	}

	return false;
}

void GoogleDataResource::aboutToQuit()
{
	// TODO: any cleanup you need to do while there is still an active
	// event loop. The resource will terminate after this method returns
}

void GoogleDataResource::configure( WId windowId )
{
	Q_UNUSED( windowId );
	char *user, *pass;
	int result = -1;
	QByteArray byteUser, bytePass;

	if (!dlgConf)
		dlgConf = new dlgGoogleDataConf;

	if (windowId && dlgConf)
		KWindowSystem::setMainWindow(dlgConf, windowId);

	dlgConf->exec();

	byteUser = dlgConf->eAccount->text().toLocal8Bit();
	bytePass = dlgConf->ePass->text().toLocal8Bit();
	user = const_cast<char *>(byteUser.constData());
	pass = const_cast<char *>(bytePass.constData());
	if (user)
		if (pass)
			result = gcal_get_authentication(gcal, user, pass);

	/* TODO: in case of authentication error, display an error
	 * message.
	 */
	if (!result)
		authenticated = true;

	synchronize();
}

void GoogleDataResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{

	Q_UNUSED(collection);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	Item newItem;
	int result;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_title(contact, const_cast<char *>(t_byte.constData()));

	temp = addressee.fullEmail();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_email(contact, const_cast<char *>(t_byte.constData()));

	/* TODO: add remaining fields */

	if ((result = gcal_add_contact(gcal, contact))) {
		kError() << "Failed adding new contact"
			 << "name: " << addressee.realName()
			 << "email: " << addressee.fullEmail();
		const QString message = i18nc("@info:status",
					      "Failed adding new contact");
		emit error(message);
		emit status(Broken, message);

	}
	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));
	//FIXME: this guy is const... how to supply the etag/url?
	//item.setRemoteId(urlEtag.url());

	/* cleanup */
	gcal_contact_delete(contact);

}

void GoogleDataResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED(parts);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	KABC::Key key;
	QString temp;
	int result;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	gcal_contact_set_title(contact, const_cast<char *>(qPrintable(temp)));

	temp = addressee.fullEmail();
	gcal_contact_set_email(contact, const_cast<char *>(qPrintable(temp)));

	temp = addressee.uid();
	gcal_contact_set_id(contact, const_cast<char *>(qPrintable(temp)));

	/* I suppose that this retrieves the first element in the key list */
	key = addressee.keys()[0];
	temp = key.id();
	gcal_contact_set_etag(contact, const_cast<char *>(qPrintable(temp)));

	/* TODO: add remaining fields */

	if ((result = gcal_update_contact(gcal, contact)))
		exit(1);

	/* Updates the ETag/url: I suppose that akonadi will save this object */
	temp = gcal_contact_get_url(contact);
	addressee.setUid(temp);

	temp = gcal_contact_get_etag(contact);
	key.setId(temp);
	addressee.insertKey(key);

	gcal_contact_delete(contact);

}

void GoogleDataResource::itemRemoved( const Akonadi::Item &item )
{
	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	int result;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, const_cast<char *>(t_byte.constData()));

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, const_cast<char *>(t_byte.constData()));

	if ((result = gcal_erase_contact(gcal, contact))) {
		kError() << "Failed deleting contact";
		const QString message = i18nc("@info:status",
					      "Failed deleting new contact");
		emit error(message);
		emit status(Broken, message);

	}

	gcal_contact_delete(contact);
}

AKONADI_RESOURCE_MAIN( GoogleDataResource )

#include "googledataresource.moc"
<commit_msg>Making sure that gcal_contact_array is correctly initialized.<commit_after>#include "googledataresource.h"

#include "settings.h"
#include "settingsadaptor.h"

#include <QtDBus/QDBusConnection>
#include <kabc/addressee.h>
#include <kabc/phonenumber.h>
#include <kabc/key.h>
#include <kabc/errorhandler.h>
#include <qstring.h>
#include <KWindowSystem>
#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>
#include <KUrl>

extern "C" {
#include <gcalendar.h>
#include <gcontact.h>
#include <gcal_status.h>
}

/** FIXME: for some reason the 'retrieveItem' functions is not being called.
 * this makes the entries to lack its contents (name, email, etc).
 * I should investigate why and fix, for while this is a workaround:
 * I report the payload in the 'retrieveItems' function.
 */
#define ITEM_BUG_WTF

using namespace Akonadi;

GoogleDataResource::GoogleDataResource( const QString &id )
	: ResourceBase(id), dlgConf(0), authenticated(false)
{
	new SettingsAdaptor( Settings::self() );
	QDBusConnection::sessionBus().registerObject(
		QLatin1String( "/Settings" ), Settings::self(),
		QDBusConnection::ExportAdaptors );

	changeRecorder()->itemFetchScope().fetchFullPayload();

	if (!(gcal = gcal_new(GCONTACT)))
		exit(1);
	gcal_set_store_xml(gcal, 1);
	all_contacts.length = 0;
	all_contacts.entries = NULL;
}

GoogleDataResource::~GoogleDataResource()
{
	gcal_delete(gcal);
	gcal_cleanup_contacts(&all_contacts);
	if (dlgConf)
		delete dlgConf;
}

void GoogleDataResource::retrieveCollections()
{
	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	Collection c;
	c.setParent(Collection::root());
	c.setRemoteId("google-contacts");
	c.setName(name());

	QStringList mimeTypes;
	mimeTypes << "text/directory";
	c.setContentMimeTypes(mimeTypes);

	Collection::List list;
	list << c;
	collectionsRetrieved(list);

}

void GoogleDataResource::retrieveItems( const Akonadi::Collection &collection )
{
	Q_UNUSED( collection );

	Item::List items;
	int result;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	/* Downloading the contacts can be slow and it is blocking. Will
	 * it mess up with akonadi?
	 */
	if ((result = gcal_get_contacts(gcal, &all_contacts)))
		exit(1);

	/* Each google entry has a unique ID and edit_url */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		Item item(QLatin1String("text/directory"));
		gcal_contact_t contact = gcal_contact_element(&all_contacts, i);

#ifdef ITEM_BUG_WTF
		KABC::Addressee addressee;
		KABC::PhoneNumber number;
		QString temp;

		/* name */
		temp = gcal_contact_get_title(contact);
		addressee.setNameFromString(temp);
		/* email */
		temp = gcal_contact_get_email(contact);
		addressee.insertEmail(temp, true);
		/* TODO: telefone, address, etc */

		item.setPayload<KABC::Addressee>(addressee);

		/* remoteID: etag+edit_url */
		KUrl urlEtag(gcal_contact_get_url(contact));
		urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

#endif

		item.setRemoteId(urlEtag.url());

		items << item;
	}

	itemsRetrieved(items);
}

bool GoogleDataResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED( parts );
	const QString entry_id = item.remoteId();
	QString temp;
	Item newItem(item);
	gcal_contact_t contact;
	KABC::Addressee addressee;
	KABC::PhoneNumber number;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return false;
	}

	/*
	 * And another question, are the requests in the same sequence that
	 * I informed in 'retrieveItems'? For while, I try to locate the entry...
	 */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		contact = gcal_contact_element(&all_contacts, i);
		if (entry_id == gcal_contact_get_id(contact)) {
			/* name */
			temp = gcal_contact_get_title(contact);
			addressee.setNameFromString(temp);

			/* email */
			temp = gcal_contact_get_email(contact);
			addressee.insertEmail(temp, true);

			/* TODO: telefone, address, etc */

			/* remoteID: etag+edit_url */
			KUrl urlEtag(gcal_contact_get_url(contact));
			urlEtag.addQueryItem("etag",
					     gcal_contact_get_etag(contact));

			newItem.setPayload<KABC::Addressee>(addressee);
			newItem.setRemoteId(urlEtag.url());
                        itemRetrieved(newItem);
			return true;
		}

	}

	return false;
}

void GoogleDataResource::aboutToQuit()
{
	// TODO: any cleanup you need to do while there is still an active
	// event loop. The resource will terminate after this method returns
}

void GoogleDataResource::configure( WId windowId )
{
	Q_UNUSED( windowId );
	char *user, *pass;
	int result = -1;
	QByteArray byteUser, bytePass;

	if (!dlgConf)
		dlgConf = new dlgGoogleDataConf;

	if (windowId && dlgConf)
		KWindowSystem::setMainWindow(dlgConf, windowId);

	dlgConf->exec();

	byteUser = dlgConf->eAccount->text().toLocal8Bit();
	bytePass = dlgConf->ePass->text().toLocal8Bit();
	user = const_cast<char *>(byteUser.constData());
	pass = const_cast<char *>(bytePass.constData());
	if (user)
		if (pass)
			result = gcal_get_authentication(gcal, user, pass);

	/* TODO: in case of authentication error, display an error
	 * message.
	 */
	if (!result)
		authenticated = true;

	synchronize();
}

void GoogleDataResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{

	Q_UNUSED(collection);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	Item newItem;
	int result;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_title(contact, const_cast<char *>(t_byte.constData()));

	temp = addressee.fullEmail();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_email(contact, const_cast<char *>(t_byte.constData()));

	/* TODO: add remaining fields */

	if ((result = gcal_add_contact(gcal, contact))) {
		kError() << "Failed adding new contact"
			 << "name: " << addressee.realName()
			 << "email: " << addressee.fullEmail();
		const QString message = i18nc("@info:status",
					      "Failed adding new contact");
		emit error(message);
		emit status(Broken, message);

	}
	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));
	//FIXME: this guy is const... how to supply the etag/url?
	//item.setRemoteId(urlEtag.url());

	/* cleanup */
	gcal_contact_delete(contact);

}

void GoogleDataResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED(parts);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	KABC::Key key;
	QString temp;
	int result;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	gcal_contact_set_title(contact, const_cast<char *>(qPrintable(temp)));

	temp = addressee.fullEmail();
	gcal_contact_set_email(contact, const_cast<char *>(qPrintable(temp)));

	temp = addressee.uid();
	gcal_contact_set_id(contact, const_cast<char *>(qPrintable(temp)));

	/* I suppose that this retrieves the first element in the key list */
	key = addressee.keys()[0];
	temp = key.id();
	gcal_contact_set_etag(contact, const_cast<char *>(qPrintable(temp)));

	/* TODO: add remaining fields */

	if ((result = gcal_update_contact(gcal, contact)))
		exit(1);

	/* Updates the ETag/url: I suppose that akonadi will save this object */
	temp = gcal_contact_get_url(contact);
	addressee.setUid(temp);

	temp = gcal_contact_get_etag(contact);
	key.setId(temp);
	addressee.insertKey(key);

	gcal_contact_delete(contact);

}

void GoogleDataResource::itemRemoved( const Akonadi::Item &item )
{
	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	int result;

	if (!authenticated) {
		kError() << "No athentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, const_cast<char *>(t_byte.constData()));

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, const_cast<char *>(t_byte.constData()));

	if ((result = gcal_erase_contact(gcal, contact))) {
		kError() << "Failed deleting contact";
		const QString message = i18nc("@info:status",
					      "Failed deleting new contact");
		emit error(message);
		emit status(Broken, message);

	}

	gcal_contact_delete(contact);
}

AKONADI_RESOURCE_MAIN( GoogleDataResource )

#include "googledataresource.moc"
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
#include "modules/rtp_rtcp/source/rtcp_receiver.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/clock.h"

namespace webrtc {
namespace {

constexpr int kRtcpIntervalMs = 1000;

class NullModuleRtpRtcp : public RTCPReceiver::ModuleRtpRtcp {
 public:
  void SetTmmbn(std::vector<rtcp::TmmbItem>) override {}
  void OnRequestSendReport() override {}
  void OnReceivedNack(const std::vector<uint16_t>&) override {}
  void OnReceivedRtcpReportBlocks(const ReportBlockList&) override {}
};

}  // namespace

void FuzzOneInput(const uint8_t* data, size_t size) {
  NullModuleRtpRtcp rtp_rtcp_module;
  SimulatedClock clock(1234);

  RTCPReceiver receiver(&clock, false, nullptr, nullptr, nullptr, nullptr,
                        nullptr, kRtcpIntervalMs, &rtp_rtcp_module);

  receiver.IncomingPacket(data, size);
}
}  // namespace webrtc
<commit_msg>Fix timeout in rtcp_receiver_fuzzer - limit input length<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
#include "modules/rtp_rtcp/source/rtcp_receiver.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/clock.h"

namespace webrtc {
namespace {

constexpr int kRtcpIntervalMs = 1000;

// RTCP is typically sent over UDP, which has a maximum payload length
// of 65535 bytes. We err on the side of caution and check a bit above that.
constexpr size_t kMaxInputLenBytes = 66000;

class NullModuleRtpRtcp : public RTCPReceiver::ModuleRtpRtcp {
 public:
  void SetTmmbn(std::vector<rtcp::TmmbItem>) override {}
  void OnRequestSendReport() override {}
  void OnReceivedNack(const std::vector<uint16_t>&) override {}
  void OnReceivedRtcpReportBlocks(const ReportBlockList&) override {}
};

}  // namespace

void FuzzOneInput(const uint8_t* data, size_t size) {
  if (size > kMaxInputLenBytes) {
    return;
  }

  NullModuleRtpRtcp rtp_rtcp_module;
  SimulatedClock clock(1234);

  RTCPReceiver receiver(&clock, false, nullptr, nullptr, nullptr, nullptr,
                        nullptr, kRtcpIntervalMs, &rtp_rtcp_module);

  receiver.IncomingPacket(data, size);
}
}  // namespace webrtc
<|endoftext|>


<commit_before>#include <pangolin/log/packetstream.h>

namespace pangolin {

size_t PacketStream::readUINT()
{
    size_t n = 0;
    size_t v = get();
    uint32_t shift = 0;
    while (good() && (v & 0x80))
    {
        n |= (v & 0x7F) << shift;
        shift += 7;
        v = get();
    }
    if (!good())
        return static_cast<size_t>(-1);
    return n | (v & 0x7F) << shift;
}

int64_t PacketStream::readTimestamp()
{
    int64_t time_us;
    read(reinterpret_cast<char*>(&time_us), sizeof(int64_t));
    return time_us;
}

pangoTagType PacketStream::readTag()
{
    auto r = peekTag();
    _tag = 0;
    return r;
}

pangoTagType PacketStream::readTag(pangoTagType x)
{
    auto r = readTag();
    if (r != x)
        throw std::runtime_error(("Tag mismatch error: expected tag '" + tagName(r) + "' does not match found tag '" + tagName(x) + "'").c_str());
    return r;
}

pangoTagType PacketStream::peekTag()
{
    if (!_tag)
    {
        _tag = 0;
        Base::read(reinterpret_cast<char*>(&_tag), TAG_LENGTH);
        if (!good())
            _tag = TAG_END;
    }
    return _tag;
}

char PacketStream::get()
{
    _tag = 0;
    return Base::get();
}

size_t PacketStream::read(char* target, size_t len)
{
    _tag = 0;
    Base::read(target, len);
    return gcount();
}

size_t PacketStream::skip(size_t len)
{
    ignore(len);
    _tag = 0;
    return len;
}

std::streampos PacketStream::tellg()
{
    if (_tag) {
        return Base::tellg() - std::streamoff(TAG_LENGTH);
    }else{
        return Base::tellg();
    }
}

void PacketStream::seekg(std::streampos target)
{
    if (seekable()) {
        cclear();
        Base::seekg(target);
    }
}

void PacketStream::seekg(std::streamoff off, std::ios_base::seekdir way)
{
    if (seekable()) {
        cclear();
        Base::seekg(off, way);
    }
}

static bool valid(pangoTagType t)
{
    switch (t)
    {
    case TAG_PANGO_SYNC:
        case TAG_ADD_SOURCE:
        case TAG_SRC_JSON:
        case TAG_SRC_PACKET:
        case TAG_PANGO_STATS:
        case TAG_PANGO_FOOTER:
        case TAG_END:
        case TAG_PANGO_HDR:
        case TAG_PANGO_MAGIC:
        return true;
    default:
        return false;
    }
}

pangoTagType PacketStream::syncToTag() //scan through chars one by one until the last three look like a tag
{
    peekTag();
    char * buffer = reinterpret_cast<char*>(&_tag);

    buffer[3] = 0;

    do
    {
        buffer[0] = buffer[1];
        buffer[1] = buffer[2];
        buffer[2] = get();
    }
    while (good() && !valid(_tag));

    if (!good())
        _tag = TAG_END;

    return _tag;

}

}
<commit_msg>Add missing header <stdexcept><commit_after>#include <pangolin/log/packetstream.h>
#include <stdexcept>

namespace pangolin {

size_t PacketStream::readUINT()
{
    size_t n = 0;
    size_t v = get();
    uint32_t shift = 0;
    while (good() && (v & 0x80))
    {
        n |= (v & 0x7F) << shift;
        shift += 7;
        v = get();
    }
    if (!good())
        return static_cast<size_t>(-1);
    return n | (v & 0x7F) << shift;
}

int64_t PacketStream::readTimestamp()
{
    int64_t time_us;
    read(reinterpret_cast<char*>(&time_us), sizeof(int64_t));
    return time_us;
}

pangoTagType PacketStream::readTag()
{
    auto r = peekTag();
    _tag = 0;
    return r;
}

pangoTagType PacketStream::readTag(pangoTagType x)
{
    auto r = readTag();
    if (r != x)
        throw std::runtime_error(("Tag mismatch error: expected tag '" + tagName(r) + "' does not match found tag '" + tagName(x) + "'").c_str());
    return r;
}

pangoTagType PacketStream::peekTag()
{
    if (!_tag)
    {
        _tag = 0;
        Base::read(reinterpret_cast<char*>(&_tag), TAG_LENGTH);
        if (!good())
            _tag = TAG_END;
    }
    return _tag;
}

char PacketStream::get()
{
    _tag = 0;
    return Base::get();
}

size_t PacketStream::read(char* target, size_t len)
{
    _tag = 0;
    Base::read(target, len);
    return gcount();
}

size_t PacketStream::skip(size_t len)
{
    ignore(len);
    _tag = 0;
    return len;
}

std::streampos PacketStream::tellg()
{
    if (_tag) {
        return Base::tellg() - std::streamoff(TAG_LENGTH);
    }else{
        return Base::tellg();
    }
}

void PacketStream::seekg(std::streampos target)
{
    if (seekable()) {
        cclear();
        Base::seekg(target);
    }
}

void PacketStream::seekg(std::streamoff off, std::ios_base::seekdir way)
{
    if (seekable()) {
        cclear();
        Base::seekg(off, way);
    }
}

static bool valid(pangoTagType t)
{
    switch (t)
    {
    case TAG_PANGO_SYNC:
        case TAG_ADD_SOURCE:
        case TAG_SRC_JSON:
        case TAG_SRC_PACKET:
        case TAG_PANGO_STATS:
        case TAG_PANGO_FOOTER:
        case TAG_END:
        case TAG_PANGO_HDR:
        case TAG_PANGO_MAGIC:
        return true;
    default:
        return false;
    }
}

pangoTagType PacketStream::syncToTag() //scan through chars one by one until the last three look like a tag
{
    peekTag();
    char * buffer = reinterpret_cast<char*>(&_tag);

    buffer[3] = 0;

    do
    {
        buffer[0] = buffer[1];
        buffer[1] = buffer[2];
        buffer[2] = get();
    }
    while (good() && !valid(_tag));

    if (!good())
        _tag = TAG_END;

    return _tag;

}

}
<|endoftext|>