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

#include "contacteditor.h"

#include <QtGui>

const int MAX_AVATAR_DISPLAY_SIZE = 120;

ContactEditor::ContactEditor(QWidget *parent)
        :QWidget(parent)
{
    m_manager = 0;
    m_contactId = QContactLocalId(0);

    m_nameEdit = new QLineEdit(this);
    m_phoneEdit = new QLineEdit(this);
    m_emailEdit = new QLineEdit(this);
    m_addrEdit = new QLineEdit(this);
    m_avatarBtn = new QPushButton(tr("Set picture"), this);
    m_clearAvatarBtn = new QPushButton(tr("Clear"), this);
    m_avatarView = new QLabel(this);
    connect(m_avatarBtn, SIGNAL(clicked()), this, SLOT(avatarClicked()));
    connect(m_clearAvatarBtn, SIGNAL(clicked()), this, SLOT(clearAvatarClicked()));

    QFormLayout *detailsLayout = new QFormLayout;
    QLabel *nameLabel = new QLabel(tr("Name"), this);
    QLabel *phoneLabel = new QLabel(tr("Phone"), this);
    QLabel *emailLabel = new QLabel(tr("Email"), this);
    QLabel *addressLabel = new QLabel(tr("Address"), this);
    QLabel *avatarLabel = new QLabel(tr("Picture"), this);
    QHBoxLayout *avatarBtnLayout = new QHBoxLayout;
    avatarBtnLayout->addWidget(m_avatarBtn);
    avatarBtnLayout->addWidget(m_clearAvatarBtn);
    if (QApplication::desktop()->availableGeometry().width() < 360) {
        // Narrow screen: put label on separate line to textbox
        detailsLayout->addRow(nameLabel);
        detailsLayout->addRow(m_nameEdit);
        detailsLayout->addRow(phoneLabel);
        detailsLayout->addRow(m_phoneEdit);
        detailsLayout->addRow(emailLabel);
        detailsLayout->addRow(m_emailEdit);
        detailsLayout->addRow(addressLabel);
        detailsLayout->addRow(m_addrEdit);
        detailsLayout->addRow(avatarLabel);
        detailsLayout->addRow(avatarBtnLayout);
        detailsLayout->addRow(m_avatarView);
    } else {
        // Wide screen: put label on same line as textbox
        detailsLayout->addRow(nameLabel, m_nameEdit);
        detailsLayout->addRow(phoneLabel, m_phoneEdit);
        detailsLayout->addRow(emailLabel, m_emailEdit);
        detailsLayout->addRow(addressLabel, m_addrEdit);
        detailsLayout->addRow(avatarLabel, avatarBtnLayout);
        detailsLayout->addRow("", m_avatarView);
    }
    detailsLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
    detailsLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);

    QScrollArea *detailsScrollArea = new QScrollArea(this);
    detailsScrollArea->setWidgetResizable(true);
    QWidget *detailsContainer = new QWidget(detailsScrollArea);
    detailsContainer->setLayout(detailsLayout);
    detailsScrollArea->setWidget(detailsContainer);

    QVBoxLayout *editLayout = new QVBoxLayout;
    editLayout->addWidget(detailsScrollArea);

#ifdef Q_OS_SYMBIAN
    // In symbian "save" and "cancel" buttons are softkeys.
    m_saveBtn = new QAction(tr("Save"), this);
    m_saveBtn->setSoftKeyRole(QAction::PositiveSoftKey);
    addAction(m_saveBtn);
    connect(m_saveBtn, SIGNAL(triggered(bool)), this, SLOT(saveClicked()));
    m_cancelBtn = new QAction(tr("Cancel"), this);
    m_cancelBtn->setSoftKeyRole(QAction::NegativeSoftKey);
    addAction(m_cancelBtn);
    connect(m_cancelBtn, SIGNAL(triggered(bool)), this, SLOT(cancelClicked()));
#else
    m_saveBtn = new QPushButton(tr("&Save"), this);
    m_saveBtn->setDefault(true);
    connect(m_saveBtn, SIGNAL(clicked()), this, SLOT(saveClicked()));
    m_cancelBtn = new QPushButton(tr("&Cancel"), this);
    connect(m_cancelBtn, SIGNAL(clicked()), this, SLOT(cancelClicked()));
    QHBoxLayout *btnLayout = new QHBoxLayout;
    btnLayout->addWidget(m_saveBtn);
    btnLayout->addWidget(m_cancelBtn);
    editLayout->addLayout(btnLayout);
#endif

    setLayout(editLayout);
}

ContactEditor::~ContactEditor()
{
}

void ContactEditor::setCurrentContact(QContactManager* manager, QContactLocalId currentId)
{
    m_manager = manager;
    m_contactId = currentId;
    m_newAvatarPath = QString();

    // Clear UI
    m_nameEdit->clear();
    m_phoneEdit->clear();
    m_emailEdit->clear();
    m_addrEdit->clear();

    if (manager == 0) {
        m_saveBtn->setEnabled(false);
        return;
    }

    // enable the UI.
    m_saveBtn->setEnabled(true);

    // otherwise, build from the contact details.
    QContact curr;
    if (m_contactId != QContactLocalId(0))
        curr = manager->contact(m_contactId);

    // Disable fields & buttons according to what the backend supports
    QMap<QString, QContactDetailDefinition> defs = m_manager->detailDefinitions(QContactType::TypeContact);

    // name
    //QContactName nm = curr.detail(QContactName::DefinitionName);
    if (m_contactId != QContactLocalId(0))
        m_nameEdit->setText(manager->synthesizedContactDisplayLabel(curr));

    // phonenumber
    QContactPhoneNumber phn = curr.detail(QContactPhoneNumber::DefinitionName);
    m_phoneEdit->setText(phn.value(QContactPhoneNumber::FieldNumber));

    // email
    if (defs.contains(QContactEmailAddress::DefinitionName)) {
        QContactEmailAddress em = curr.detail(QContactEmailAddress::DefinitionName);
        m_emailEdit->setText(em.value(QContactEmailAddress::FieldEmailAddress));
        m_emailEdit->setReadOnly(false);
    } else {
        m_emailEdit->setText("<not supported>");
        m_emailEdit->setReadOnly(true);
    }

    // address
    if (defs.contains(QContactAddress::DefinitionName)) {
        QContactAddress adr = curr.detail(QContactAddress::DefinitionName);
        m_addrEdit->setText(adr.value(QContactAddress::FieldStreet)); // ugly hack.
        m_addrEdit->setReadOnly(false);
    } else {
        m_addrEdit->setText("<not supported>");
        m_addrEdit->setReadOnly(true);
    }

    // avatar viewer
    if (defs.contains(QContactAvatar::DefinitionName)
        && defs.contains(QContactThumbnail::DefinitionName)) {
        m_avatarBtn->setEnabled(true);
        QContactAvatar av = curr.detail(QContactAvatar::DefinitionName);
        QContactThumbnail thumb = curr.detail(QContactThumbnail::DefinitionName);
        m_avatarView->clear();
        m_newAvatarPath = av.imageUrl().toLocalFile();
        m_thumbnail = thumb.thumbnail();
        if (m_thumbnail.isNull()) {
            if (m_newAvatarPath.isEmpty()) {
                m_avatarView->clear();
                m_clearAvatarBtn->setDisabled(true);
            } else {
                setAvatarPixmap(QPixmap(av.imageUrl().toLocalFile()));
                m_thumbnail = QImage(av.imageUrl().toLocalFile());
            }
        } else {
            setAvatarPixmap(QPixmap::fromImage(m_thumbnail));
        }
    } else {
        m_avatarBtn->setDisabled(true);
        m_clearAvatarBtn->setDisabled(true);
    }
}

QString ContactEditor::nameField()
{
    // return the field which the name data should be saved in.
    if (!m_manager)
        return QString();

    QMap<QString, QContactDetailDefinition> defs = m_manager->detailDefinitions(QContactType::TypeContact);
    QContactDetailDefinition nameDef = defs.value(QContactName::DefinitionName);
    if (nameDef.fields().keys().contains(QContactName::FieldCustomLabel)) {
        return QString(QLatin1String(QContactName::FieldCustomLabel));
    } else if (nameDef.fields().keys().contains(QContactName::FieldFirstName)) {
        return QString(QLatin1String(QContactName::FieldFirstName));
    } else {
        return QString();
    }
}

void ContactEditor::setAvatarPixmap(const QPixmap &pixmap)
{
    if (pixmap.isNull())
        return;
    QPixmap scaled = pixmap.scaled(QSize(MAX_AVATAR_DISPLAY_SIZE, MAX_AVATAR_DISPLAY_SIZE),
                                   Qt::KeepAspectRatio,
                                   Qt::SmoothTransformation);
    m_avatarView->setPixmap(scaled);
    m_avatarView->setMaximumSize(scaled.size());
    m_clearAvatarBtn->setEnabled(true);
}

void ContactEditor::clearAvatarClicked()
{
    m_avatarView->clear();
    m_thumbnail = QImage();
    m_newAvatarPath.clear();
    m_clearAvatarBtn->setDisabled(true);
}

void ContactEditor::avatarClicked()
{
    // put up a file dialog, and update the new avatar path.
    QString fileName = QFileDialog::getOpenFileName(this,
       tr("Select Contact Picture"), ".", tr("Image Files (*.png *.jpg *.bmp)"));

    if (!fileName.isEmpty()) {
        m_newAvatarPath = fileName;
        m_thumbnail = QImage(m_newAvatarPath);
        setAvatarPixmap(QPixmap::fromImage(m_thumbnail));
    }
}

void ContactEditor::saveClicked()
{
    if (!m_manager) {
        qWarning() << "No manager selected; cannot save.";
    } else {
        QContact curr;
        if (m_contactId != QContactLocalId(0))
            curr = m_manager->contact(m_contactId);

        if (m_nameEdit->text().isEmpty()) {
            QMessageBox::information(this, "Failed!", "You must give a name for the contact!");
            return;
        }

        if (m_nameEdit->text() != m_manager->synthesizedContactDisplayLabel(curr)) {
            // if the name has changed (ie, is different to the synthed label) then save it as a custom label.
            QString saveNameField = nameField();
            if (!saveNameField.isEmpty()) {
                QContactName nm = curr.detail(QContactName::DefinitionName);
                nm.setValue(saveNameField, m_nameEdit->text());
                curr.saveDetail(&nm);
            }
        }

        QContactPhoneNumber phn = curr.detail(QContactPhoneNumber::DefinitionName);
        phn.setNumber(m_phoneEdit->text());
        curr.saveDetail(&phn);

        if (!m_emailEdit->isReadOnly()) {
            QContactEmailAddress em = curr.detail(QContactEmailAddress::DefinitionName);
            em.setEmailAddress(m_emailEdit->text());
            curr.saveDetail(&em);
        }

        if (!m_addrEdit->isReadOnly()) {
            QContactAddress adr = curr.detail(QContactAddress::DefinitionName);
            adr.setStreet(m_addrEdit->text());
            curr.saveDetail(&adr);
        }

        if (m_avatarBtn->isEnabled()) {
            QContactAvatar av = curr.detail(QContactAvatar::DefinitionName);
            av.setImageUrl(QUrl(m_newAvatarPath));
            curr.saveDetail(&av);

            QContactThumbnail thumb = curr.detail(QContactThumbnail::DefinitionName);
            QImage img(m_thumbnail);
            thumb.setThumbnail(img);
            curr.saveDetail(&thumb);
        }

        bool success = m_manager->saveContact(&curr);
        if (!success)
            QMessageBox::information(this, "Failed!", QString("Failed to save contact!\n(error code %1)").arg(m_manager->error()));
    }

    emit showListPage();
}

void ContactEditor::cancelClicked()
{
    emit showListPage();
}
<commit_msg>Allow avatars in samplephonebook when either Avatar or Image is supported<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
**     the names of its contributors may be used to endorse or promote
**     products derived from this software without specific prior written
**     permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/

#include "contacteditor.h"

#include <QtGui>

const int MAX_AVATAR_DISPLAY_SIZE = 120;

ContactEditor::ContactEditor(QWidget *parent)
        :QWidget(parent)
{
    m_manager = 0;
    m_contactId = QContactLocalId(0);

    m_nameEdit = new QLineEdit(this);
    m_phoneEdit = new QLineEdit(this);
    m_emailEdit = new QLineEdit(this);
    m_addrEdit = new QLineEdit(this);
    m_avatarBtn = new QPushButton(tr("Set picture"), this);
    m_clearAvatarBtn = new QPushButton(tr("Clear"), this);
    m_avatarView = new QLabel(this);
    connect(m_avatarBtn, SIGNAL(clicked()), this, SLOT(avatarClicked()));
    connect(m_clearAvatarBtn, SIGNAL(clicked()), this, SLOT(clearAvatarClicked()));

    QFormLayout *detailsLayout = new QFormLayout;
    QLabel *nameLabel = new QLabel(tr("Name"), this);
    QLabel *phoneLabel = new QLabel(tr("Phone"), this);
    QLabel *emailLabel = new QLabel(tr("Email"), this);
    QLabel *addressLabel = new QLabel(tr("Address"), this);
    QLabel *avatarLabel = new QLabel(tr("Picture"), this);
    QHBoxLayout *avatarBtnLayout = new QHBoxLayout;
    avatarBtnLayout->addWidget(m_avatarBtn);
    avatarBtnLayout->addWidget(m_clearAvatarBtn);
    if (QApplication::desktop()->availableGeometry().width() < 360) {
        // Narrow screen: put label on separate line to textbox
        detailsLayout->addRow(nameLabel);
        detailsLayout->addRow(m_nameEdit);
        detailsLayout->addRow(phoneLabel);
        detailsLayout->addRow(m_phoneEdit);
        detailsLayout->addRow(emailLabel);
        detailsLayout->addRow(m_emailEdit);
        detailsLayout->addRow(addressLabel);
        detailsLayout->addRow(m_addrEdit);
        detailsLayout->addRow(avatarLabel);
        detailsLayout->addRow(avatarBtnLayout);
        detailsLayout->addRow(m_avatarView);
    } else {
        // Wide screen: put label on same line as textbox
        detailsLayout->addRow(nameLabel, m_nameEdit);
        detailsLayout->addRow(phoneLabel, m_phoneEdit);
        detailsLayout->addRow(emailLabel, m_emailEdit);
        detailsLayout->addRow(addressLabel, m_addrEdit);
        detailsLayout->addRow(avatarLabel, avatarBtnLayout);
        detailsLayout->addRow("", m_avatarView);
    }
    detailsLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
    detailsLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);

    QScrollArea *detailsScrollArea = new QScrollArea(this);
    detailsScrollArea->setWidgetResizable(true);
    QWidget *detailsContainer = new QWidget(detailsScrollArea);
    detailsContainer->setLayout(detailsLayout);
    detailsScrollArea->setWidget(detailsContainer);

    QVBoxLayout *editLayout = new QVBoxLayout;
    editLayout->addWidget(detailsScrollArea);

#ifdef Q_OS_SYMBIAN
    // In symbian "save" and "cancel" buttons are softkeys.
    m_saveBtn = new QAction(tr("Save"), this);
    m_saveBtn->setSoftKeyRole(QAction::PositiveSoftKey);
    addAction(m_saveBtn);
    connect(m_saveBtn, SIGNAL(triggered(bool)), this, SLOT(saveClicked()));
    m_cancelBtn = new QAction(tr("Cancel"), this);
    m_cancelBtn->setSoftKeyRole(QAction::NegativeSoftKey);
    addAction(m_cancelBtn);
    connect(m_cancelBtn, SIGNAL(triggered(bool)), this, SLOT(cancelClicked()));
#else
    m_saveBtn = new QPushButton(tr("&Save"), this);
    m_saveBtn->setDefault(true);
    connect(m_saveBtn, SIGNAL(clicked()), this, SLOT(saveClicked()));
    m_cancelBtn = new QPushButton(tr("&Cancel"), this);
    connect(m_cancelBtn, SIGNAL(clicked()), this, SLOT(cancelClicked()));
    QHBoxLayout *btnLayout = new QHBoxLayout;
    btnLayout->addWidget(m_saveBtn);
    btnLayout->addWidget(m_cancelBtn);
    editLayout->addLayout(btnLayout);
#endif

    setLayout(editLayout);
}

ContactEditor::~ContactEditor()
{
}

void ContactEditor::setCurrentContact(QContactManager* manager, QContactLocalId currentId)
{
    m_manager = manager;
    m_contactId = currentId;
    m_newAvatarPath = QString();

    // Clear UI
    m_nameEdit->clear();
    m_phoneEdit->clear();
    m_emailEdit->clear();
    m_addrEdit->clear();

    if (manager == 0) {
        m_saveBtn->setEnabled(false);
        return;
    }

    // enable the UI.
    m_saveBtn->setEnabled(true);

    // otherwise, build from the contact details.
    QContact curr;
    if (m_contactId != QContactLocalId(0))
        curr = manager->contact(m_contactId);

    // Disable fields & buttons according to what the backend supports
    QMap<QString, QContactDetailDefinition> defs = m_manager->detailDefinitions(QContactType::TypeContact);

    // name
    //QContactName nm = curr.detail(QContactName::DefinitionName);
    if (m_contactId != QContactLocalId(0))
        m_nameEdit->setText(manager->synthesizedContactDisplayLabel(curr));

    // phonenumber
    QContactPhoneNumber phn = curr.detail(QContactPhoneNumber::DefinitionName);
    m_phoneEdit->setText(phn.value(QContactPhoneNumber::FieldNumber));

    // email
    if (defs.contains(QContactEmailAddress::DefinitionName)) {
        QContactEmailAddress em = curr.detail(QContactEmailAddress::DefinitionName);
        m_emailEdit->setText(em.value(QContactEmailAddress::FieldEmailAddress));
        m_emailEdit->setReadOnly(false);
    } else {
        m_emailEdit->setText("<not supported>");
        m_emailEdit->setReadOnly(true);
    }

    // address
    if (defs.contains(QContactAddress::DefinitionName)) {
        QContactAddress adr = curr.detail(QContactAddress::DefinitionName);
        m_addrEdit->setText(adr.value(QContactAddress::FieldStreet)); // ugly hack.
        m_addrEdit->setReadOnly(false);
    } else {
        m_addrEdit->setText("<not supported>");
        m_addrEdit->setReadOnly(true);
    }

    // avatar viewer
    if (defs.contains(QContactAvatar::DefinitionName)
        || defs.contains(QContactThumbnail::DefinitionName)) {
        m_avatarBtn->setEnabled(true);
        QContactAvatar av = curr.detail(QContactAvatar::DefinitionName);
        QContactThumbnail thumb = curr.detail(QContactThumbnail::DefinitionName);
        m_avatarView->clear();
        m_newAvatarPath = av.imageUrl().toLocalFile();
        m_thumbnail = thumb.thumbnail();
        if (m_thumbnail.isNull()) {
            if (m_newAvatarPath.isEmpty()) {
                m_avatarView->clear();
                m_clearAvatarBtn->setDisabled(true);
            } else {
                setAvatarPixmap(QPixmap(av.imageUrl().toLocalFile()));
                m_thumbnail = QImage(av.imageUrl().toLocalFile());
            }
        } else {
            setAvatarPixmap(QPixmap::fromImage(m_thumbnail));
        }
    } else {
        m_avatarBtn->setDisabled(true);
        m_clearAvatarBtn->setDisabled(true);
    }
}

QString ContactEditor::nameField()
{
    // return the field which the name data should be saved in.
    if (!m_manager)
        return QString();

    QMap<QString, QContactDetailDefinition> defs = m_manager->detailDefinitions(QContactType::TypeContact);
    QContactDetailDefinition nameDef = defs.value(QContactName::DefinitionName);
    if (nameDef.fields().keys().contains(QContactName::FieldCustomLabel)) {
        return QString(QLatin1String(QContactName::FieldCustomLabel));
    } else if (nameDef.fields().keys().contains(QContactName::FieldFirstName)) {
        return QString(QLatin1String(QContactName::FieldFirstName));
    } else {
        return QString();
    }
}

void ContactEditor::setAvatarPixmap(const QPixmap &pixmap)
{
    if (pixmap.isNull())
        return;
    QPixmap scaled = pixmap.scaled(QSize(MAX_AVATAR_DISPLAY_SIZE, MAX_AVATAR_DISPLAY_SIZE),
                                   Qt::KeepAspectRatio,
                                   Qt::SmoothTransformation);
    m_avatarView->setPixmap(scaled);
    m_avatarView->setMaximumSize(scaled.size());
    m_clearAvatarBtn->setEnabled(true);
}

void ContactEditor::clearAvatarClicked()
{
    m_avatarView->clear();
    m_thumbnail = QImage();
    m_newAvatarPath.clear();
    m_clearAvatarBtn->setDisabled(true);
}

void ContactEditor::avatarClicked()
{
    // put up a file dialog, and update the new avatar path.
    QString fileName = QFileDialog::getOpenFileName(this,
       tr("Select Contact Picture"), ".", tr("Image Files (*.png *.jpg *.bmp)"));

    if (!fileName.isEmpty()) {
        m_newAvatarPath = fileName;
        m_thumbnail = QImage(m_newAvatarPath);
        setAvatarPixmap(QPixmap::fromImage(m_thumbnail));
    }
}

void ContactEditor::saveClicked()
{
    if (!m_manager) {
        qWarning() << "No manager selected; cannot save.";
    } else {
        QContact curr;
        if (m_contactId != QContactLocalId(0))
            curr = m_manager->contact(m_contactId);

        if (m_nameEdit->text().isEmpty()) {
            QMessageBox::information(this, "Failed!", "You must give a name for the contact!");
            return;
        }

        if (m_nameEdit->text() != m_manager->synthesizedContactDisplayLabel(curr)) {
            // if the name has changed (ie, is different to the synthed label) then save it as a custom label.
            QString saveNameField = nameField();
            if (!saveNameField.isEmpty()) {
                QContactName nm = curr.detail(QContactName::DefinitionName);
                nm.setValue(saveNameField, m_nameEdit->text());
                curr.saveDetail(&nm);
            }
        }

        QContactPhoneNumber phn = curr.detail(QContactPhoneNumber::DefinitionName);
        phn.setNumber(m_phoneEdit->text());
        curr.saveDetail(&phn);

        if (!m_emailEdit->isReadOnly()) {
            QContactEmailAddress em = curr.detail(QContactEmailAddress::DefinitionName);
            em.setEmailAddress(m_emailEdit->text());
            curr.saveDetail(&em);
        }

        if (!m_addrEdit->isReadOnly()) {
            QContactAddress adr = curr.detail(QContactAddress::DefinitionName);
            adr.setStreet(m_addrEdit->text());
            curr.saveDetail(&adr);
        }

        if (m_avatarBtn->isEnabled()) {
            QContactAvatar av = curr.detail(QContactAvatar::DefinitionName);
            av.setImageUrl(QUrl(m_newAvatarPath));
            curr.saveDetail(&av);

            QContactThumbnail thumb = curr.detail(QContactThumbnail::DefinitionName);
            QImage img(m_thumbnail);
            thumb.setThumbnail(img);
            curr.saveDetail(&thumb);
        }

        curr = m_manager->compatibleContact(curr);
        bool success = m_manager->saveContact(&curr);
        if (!success)
            QMessageBox::information(this, "Failed!", QString("Failed to save contact!\n(error code %1)").arg(m_manager->error()));
    }

    emit showListPage();
}

void ContactEditor::cancelClicked()
{
    emit showListPage();
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: stbitem.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 17:20:14 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SFXSTBITEM_HXX
#define _SFXSTBITEM_HXX

#ifndef _SAL_CONFIG_H_
#include "sal/config.h"
#endif

#ifndef INCLUDED_SFX2_DLLAPI_H
#include "sfx2/dllapi.h"
#endif

#ifndef _SFXPOOLITEM_HXX
#include <svtools/poolitem.hxx>
#endif
#ifndef _SVTOOLS_STATUSBARCONTROLLER_HXX
#include <svtools/statusbarcontroller.hxx>
#endif

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

class SfxModule;
class StatusBar;
class SfxStatusBarControl;
class SfxBindings;

svt::StatusbarController* SAL_CALL SfxStatusBarControllerFactory(
    const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& rFrame,
    StatusBar* pStatusBar,
    unsigned short nID,
    const ::rtl::OUString& aCommandURL );
typedef SfxStatusBarControl* (*SfxStatusBarControlCtor)( USHORT nSlotId, USHORT nId, StatusBar &rStb );

struct SfxStbCtrlFactory
{
    SfxStatusBarControlCtor pCtor;
    TypeId                  nTypeId;
    USHORT                  nSlotId;

    SfxStbCtrlFactory( SfxStatusBarControlCtor pTheCtor,
            TypeId nTheTypeId, USHORT nTheSlotId ):
        pCtor(pTheCtor),
        nTypeId(nTheTypeId),
        nSlotId(nTheSlotId)
    {}
};

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

class CommandEvent;
class MouseEvent;
class UserDrawEvent;

class SFX2_DLLPUBLIC SfxStatusBarControl: public svt::StatusbarController
{
    USHORT          nSlotId;
    USHORT          nId;
    StatusBar*      pBar;

protected:
    // new controller API
    // XInterface
    virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
    virtual void               SAL_CALL acquire() throw();
    virtual void               SAL_CALL release() throw();

    // XEventListener
    virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& aEvent ) throw( ::com::sun::star::uno::RuntimeException );

    // XComponent
    virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);

    // XStatusListener
    virtual void SAL_CALL statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event )
        throw ( ::com::sun::star::uno::RuntimeException );

    // XStatusbarController
    virtual ::sal_Bool SAL_CALL mouseButtonDown( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
    virtual ::sal_Bool SAL_CALL mouseMove( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
    virtual ::sal_Bool SAL_CALL mouseButtonUp( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL command( const ::com::sun::star::awt::Point& aPos,
                                    ::sal_Int32 nCommand,
                                    ::sal_Bool bMouseEvent,
                                    const ::com::sun::star::uno::Any& aData ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL paint( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >& xGraphics,
                                    const ::com::sun::star::awt::Rectangle& rOutputRectangle,
                                    ::sal_Int32 nItemId, ::sal_Int32 nStyle ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL click() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL doubleClick() throw (::com::sun::star::uno::RuntimeException);

    // Old sfx2 interface
    virtual void    StateChanged( USHORT nSID, SfxItemState eState,
                                  const SfxPoolItem* pState );
    virtual void    Click();
    virtual void    DoubleClick();
    virtual void    Command( const CommandEvent& rCEvt );
    virtual BOOL    MouseButtonDown( const MouseEvent & );
    virtual BOOL    MouseMove( const MouseEvent & );
    virtual BOOL    MouseButtonUp( const MouseEvent & );
    virtual void    Paint( const UserDrawEvent &rUDEvt );

    static USHORT   convertAwtToVCLMouseButtons( sal_Int16 nAwtMouseButtons );

public:
                    SfxStatusBarControl( USHORT nSlotID, USHORT nId, StatusBar& rBar );
    virtual         ~SfxStatusBarControl();

    USHORT          GetSlotId() const { return nSlotId; }
    USHORT          GetId() const { return nId; }
    StatusBar&      GetStatusBar() const { return *pBar; }
    void            CaptureMouse();
    void            ReleaseMouse();

    static SfxStatusBarControl* CreateControl( USHORT nSlotID, USHORT nId, StatusBar *pBar, SfxModule* );
};

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

#define SFX_DECL_STATUSBAR_CONTROL() \
        static SfxStatusBarControl* CreateImpl( USHORT nSlotId, USHORT nId, StatusBar &rStb ); \
        static void RegisterControl(USHORT nSlotId = 0, SfxModule *pMod=NULL)

#define SFX_IMPL_STATUSBAR_CONTROL(Class, nItemClass) \
        SfxStatusBarControl* __EXPORT Class::CreateImpl( USHORT nSlotId, USHORT nId, StatusBar &rStb ) \
               { return new Class( nSlotId, nId, rStb ); } \
        void Class::RegisterControl(USHORT nSlotId, SfxModule *pMod) \
               { SFX_APP()->RegisterStatusBarControl( pMod, new SfxStbCtrlFactory( \
                    Class::CreateImpl, TYPE(nItemClass), nSlotId ) ); }

#endif
<commit_msg>INTEGRATION: CWS sfxcleanup (1.4.156); FILE MERGED 2006/02/26 17:09:13 mba 1.4.156.1: #132394#: remove superfluous code<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: stbitem.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2006-05-02 16:04:23 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SFXSTBITEM_HXX
#define _SFXSTBITEM_HXX

#ifndef _SAL_CONFIG_H_
#include "sal/config.h"
#endif

#ifndef INCLUDED_SFX2_DLLAPI_H
#include "sfx2/dllapi.h"
#endif

#ifndef _SFXPOOLITEM_HXX
#include <svtools/poolitem.hxx>
#endif
#ifndef _SVTOOLS_STATUSBARCONTROLLER_HXX
#include <svtools/statusbarcontroller.hxx>
#endif

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

class SfxModule;
class StatusBar;
class SfxStatusBarControl;
class SfxBindings;

svt::StatusbarController* SAL_CALL SfxStatusBarControllerFactory(
    const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& rFrame,
    StatusBar* pStatusBar,
    unsigned short nID,
    const ::rtl::OUString& aCommandURL );
typedef SfxStatusBarControl* (*SfxStatusBarControlCtor)( USHORT nSlotId, USHORT nId, StatusBar &rStb );

struct SfxStbCtrlFactory
{
    SfxStatusBarControlCtor pCtor;
    TypeId                  nTypeId;
    USHORT                  nSlotId;

    SfxStbCtrlFactory( SfxStatusBarControlCtor pTheCtor,
            TypeId nTheTypeId, USHORT nTheSlotId ):
        pCtor(pTheCtor),
        nTypeId(nTheTypeId),
        nSlotId(nTheSlotId)
    {}
};

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

class CommandEvent;
class MouseEvent;
class UserDrawEvent;

class SFX2_DLLPUBLIC SfxStatusBarControl: public svt::StatusbarController
{
    USHORT          nSlotId;
    USHORT          nId;
    StatusBar*      pBar;

protected:
    // new controller API
    // XInterface
    virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
    virtual void               SAL_CALL acquire() throw();
    virtual void               SAL_CALL release() throw();

    // XEventListener
    virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& aEvent ) throw( ::com::sun::star::uno::RuntimeException );

    // XComponent
    virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);

    // XStatusListener
    virtual void SAL_CALL statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event )
        throw ( ::com::sun::star::uno::RuntimeException );

    // XStatusbarController
    virtual ::sal_Bool SAL_CALL mouseButtonDown( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
    virtual ::sal_Bool SAL_CALL mouseMove( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
    virtual ::sal_Bool SAL_CALL mouseButtonUp( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL command( const ::com::sun::star::awt::Point& aPos,
                                    ::sal_Int32 nCommand,
                                    ::sal_Bool bMouseEvent,
                                    const ::com::sun::star::uno::Any& aData ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL paint( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >& xGraphics,
                                    const ::com::sun::star::awt::Rectangle& rOutputRectangle,
                                    ::sal_Int32 nItemId, ::sal_Int32 nStyle ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL click() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL doubleClick() throw (::com::sun::star::uno::RuntimeException);

    // Old sfx2 interface
    virtual void    StateChanged( USHORT nSID, SfxItemState eState,
                                  const SfxPoolItem* pState );
    virtual void    Click();
    virtual void    DoubleClick();
    virtual void    Command( const CommandEvent& rCEvt );
    virtual BOOL    MouseButtonDown( const MouseEvent & );
    virtual BOOL    MouseMove( const MouseEvent & );
    virtual BOOL    MouseButtonUp( const MouseEvent & );
    virtual void    Paint( const UserDrawEvent &rUDEvt );

    static USHORT   convertAwtToVCLMouseButtons( sal_Int16 nAwtMouseButtons );

public:
                    SfxStatusBarControl( USHORT nSlotID, USHORT nId, StatusBar& rBar );
    virtual         ~SfxStatusBarControl();

    USHORT          GetSlotId() const { return nSlotId; }
    USHORT          GetId() const { return nId; }
    StatusBar&      GetStatusBar() const { return *pBar; }
    void            CaptureMouse();
    void            ReleaseMouse();

    static SfxStatusBarControl* CreateControl( USHORT nSlotID, USHORT nId, StatusBar *pBar, SfxModule* );
    static void RegisterStatusBarControl(SfxModule*, SfxStbCtrlFactory*);

};

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

#define SFX_DECL_STATUSBAR_CONTROL() \
        static SfxStatusBarControl* CreateImpl( USHORT nSlotId, USHORT nId, StatusBar &rStb ); \
        static void RegisterControl(USHORT nSlotId = 0, SfxModule *pMod=NULL)

#define SFX_IMPL_STATUSBAR_CONTROL(Class, nItemClass) \
        SfxStatusBarControl* __EXPORT Class::CreateImpl( USHORT nSlotId, USHORT nId, StatusBar &rStb ) \
               { return new Class( nSlotId, nId, rStb ); } \
        void Class::RegisterControl(USHORT nSlotId, SfxModule *pMod) \
               { SfxStatusBarControl::RegisterStatusBarControl( pMod, new SfxStbCtrlFactory( \
                    Class::CreateImpl, TYPE(nItemClass), nSlotId ) ); }

#endif
<|endoftext|>


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

#include "socket.h"

#include <QLoggingCategory>

using namespace CWSGI;

Q_LOGGING_CATEGORY(CWSGI_H2, "cwsgi.http2")

#ifdef Q_CC_MSVC
#pragma pack(push)
#pragma pack(1)
#endif
struct h2_frame {
    quint8 size2;
    quint8 size1;
    quint8 size0;
    quint8 type;
    quint8 flags;
    quint8 rbit_stream_id3;
    quint8 rbit_stream_id2;
    quint8 rbit_stream_id1;
    quint8 rbit_stream_id0;
}
#ifdef Q_CC_MSVC
;
#pragma pack(pop)
#else
__attribute__ ((__packed__));
#endif

enum Flags {
    FlagSettingsAck = 0x1,
    FlagPingAck = 0x1
};

enum FrameType {
    FrameData = 0x0,
    FrameHeaders = 0x1,
    FramePriority = 0x2,
    FrameRstStream = 0x3,
    FrameSettings = 0x4,
    FramePushPromise = 0x5,
    FramePing = 0x6,
    FrameGoaway = 0x7,
    FrameWindowUpdate = 0x8,
    FrameContinuation = 0x9
};

enum ErrorCodes {
    ErrorNoError = 0x0,
    ErrorProtocolError = 0x1,
    ErrorInternalError = 0x2,
    ErrorFlowControlError = 0x3,
    ErrorSettingsTimeout = 0x4,
    ErrorStreamClosed = 0x5,
    ErrorFrameSizeError = 0x6,
    ErrorRefusedStream = 0x7,
    ErrorCancel = 0x8,
    ErrorCompressionError = 0x9,
    ErrorConnectError = 0xA,
    ErrorEnhanceYourCalm  = 0xB,
    ErrorInadequateSecurity = 0xC,
    ErrorHttp11Required = 0xD
};

enum Settings {
    SETTINGS_HEADER_TABLE_SIZE = 0x1,
    SETTINGS_ENABLE_PUSH = 0x2,
    SETTINGS_MAX_CONCURRENT_STREAMS = 0x3,
    SETTINGS_INITIAL_WINDOW_SIZE = 0x4,
    SETTINGS_MAX_FRAME_SIZE = 0x5,
    SETTINGS_MAX_HEADER_LIST_SIZE = 0x6
};

quint32 h2_be32(const char *buf) {
    const quint32 *src = reinterpret_cast<const quint32 *>(buf);
    quint32 ret = 0;
    quint8 *ptr = reinterpret_cast<quint8 *>(&ret);
    ptr[0] = static_cast<quint8>((*src >> 24) & 0xff);
    ptr[1] = static_cast<quint8>((*src >> 16) & 0xff);
    ptr[2] = static_cast<quint8>((*src >> 8) & 0xff);
    ptr[3] = static_cast<quint8>(*src & 0xff);
    return ret;
}

quint32 h2_be24(const char *buf) {
    const quint32 *src = reinterpret_cast<const quint32 *>(buf);
    quint32 ret = 0;
    quint8 *ptr = reinterpret_cast<quint8 *>(&ret);
    ptr[0] = static_cast<quint8>((*src >> 16) & 0xff);
    ptr[1] = static_cast<quint8>((*src >> 8) & 0xff);
    ptr[2] = static_cast<quint8>(*src & 0xff);
    return ret;
}

quint16 h2_be16(const char *buf) {
    const quint32 *src = reinterpret_cast<const quint32 *>(buf);
    quint16 ret = 0;
    quint8 *ptr = reinterpret_cast<quint8 *>(&ret);
    ptr[0] = static_cast<quint8>((*src >> 8) & 0xff);
    ptr[1] = static_cast<quint8>(*src & 0xff);
    return ret;
}

#define PREFACE_SIZE 24

ProtocolHttp2::ProtocolHttp2(WSGI *wsgi) : Protocol(wsgi)
{

}

ProtocolHttp2::~ProtocolHttp2()
{

}

Protocol::Type ProtocolHttp2::type() const
{
    return Http2;
}

void ProtocolHttp2::readyRead(Socket *sock, QIODevice *io) const
{
    qint64 bytesAvailable = io->bytesAvailable();
    qCDebug(CWSGI_H2) << "readyRead available" << bytesAvailable;

    int len = io->read(sock->buffer + sock->buf_size, m_bufferSize - sock->buf_size);
    bytesAvailable -= len;

    if (len > 0) {
        sock->buf_size += len;

        while (sock->buf_size) {
            qDebug() << QByteArray(sock->buffer, sock->buf_size);
            if (sock->connState == Socket::MethodLine) {
                if (sock->buf_size >= PREFACE_SIZE) {
                    if (memcmp(sock->buffer, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", 24) == 0) {
                        qCDebug(CWSGI_H2) << "Got preface" << sizeof(struct h2_frame);
                        memmove(sock->buffer, sock->buffer + PREFACE_SIZE, sock->buf_size - PREFACE_SIZE);
                        sock->buf_size -= PREFACE_SIZE;
                        sock->connState = Socket::H2Frames;

                        std::vector<std::pair<quint16, quint32>> settings;
                        sendSettings(io, settings);
                    } else {
                        qCDebug(CWSGI_H2) << "Wrong preface";
                        sendError(io);
                        sock->connectionClose();
                        return;
                        //                    return PROTOCOL_ERROR;
                    }
                }
            } else if (sock->connState == Socket::H2Frames) {
                if (sock->buf_size >= sizeof(struct h2_frame)) {
                    auto fr = reinterpret_cast<struct h2_frame *>(sock->buffer);
                    sock->pktsize = fr->size0 | (fr->size1 << 8) | (fr->size2 << 16);
                    sock->stream_id = fr->rbit_stream_id0 |
                            (fr->rbit_stream_id1 << 8) |
                            (fr->rbit_stream_id2 << 16) |
                            ((fr->rbit_stream_id3 & ~0x80) << 24); // Ignore first bit

                    qDebug() << "frame type" << fr->type << "flags" << fr->flags << "stream-id" << sock->stream_id;
                    qDebug() << "Reserved bit" << (fr->rbit_stream_id3) << (fr->rbit_stream_id3 & ~0x80) << (fr->rbit_stream_id3 & 0x80);
//                    qDebug() << "frame size" << quint32(fr->size1 | (fr->size2 << 8) | (fr->size3 << 16));
                    qDebug() << "frame size" << sock->pktsize << "available" << (sock->buf_size - sizeof(struct h2_frame));
                    if (sock->pktsize > (sock->buf_size - sizeof(struct h2_frame))) {
                        qDebug() << "need more data" << bytesAvailable;
                        return;
                    }

                    if (fr->type == FrameSettings) {
                        qDebug() << "Consumming settings";
                        QVector<std::pair<quint16, quint32>> settings;
                        uint pos = 0;
                        while (sock->pktsize > pos) {
                            quint16 identifier = h2_be16(sock->buffer + 9 + pos);
                            quint32 value = h2_be32(sock->buffer + 9 + 2 + pos);
                            settings.push_back({ identifier, value });
//                            sock->pktsize -= 6;
                            pos += 6;
                            qDebug() << "SETTINGS" << identifier << value;
                        }
                        sendSettingsAck(io);

                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FramePriority) {
                        qDebug() << "Consumming priority";
                        if (sock->pktsize != 5) {
                            // FRAME_SIZE_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        uint pos = 0;
                        while (sock->pktsize > pos) {
                            // TODO store/disable EXCLUSIVE bit
                            quint32 exclusiveAndStreamDep = h2_be32(sock->buffer + 9 + pos);
                            quint8 weigth = *reinterpret_cast<quint8 *>(sock->buffer + 9 + 4 + pos) + 1;
//                            settings.push_back({ identifier, value });
//                            sock->pktsize -= 6;

                            if (exclusiveAndStreamDep == 0) {
                                // PROTOCOL_ERROR
                                sendError(io);
                                sock->connectionClose();
                                return;
                            }

                            pos += 6;
                            qDebug() << "PRIO" << exclusiveAndStreamDep << weigth;
                        }
                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FrameHeaders) {
                        qDebug() << "Consumming headers";
                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FramePing) {
                        qCDebug(CWSGI_H2) << "Got ping" << fr->flags;
                        if (sock->pktsize != 8) {
                            // FRAME_SIZE_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        } else if (sock->stream_id) {
                            // PROTOCOL_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        if (!(fr->flags & FlagPingAck)) {
                            sendPing(io, FlagPingAck, sock->buffer + 9, 8);
                        }
                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FrameData) {
                        qCDebug(CWSGI_H2) << "Frame data" << fr->type;
                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FramePushPromise) {
                        // PROTOCOL_ERROR
                        sendError(io);
                        sock->connectionClose();
                        return;
                    } else if (fr->type == FrameRstStream) {
                        if (sock->stream_id == 0) {
                            // PROTOCOL_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        } else if (sock->pktsize != 4) {
                            // FRAME_SIZE_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FrameGoaway) {
                        sock->connectionClose();
                        return;
                    } else {
                        qCDebug(CWSGI_H2) << "Unknown frame type" << fr->type;
                        // Implementations MUST ignore and discard any frame that has a type that is unknown.
                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    }
                }
            }
        }
    }
}

int ProtocolHttp2::sendError(QIODevice *io) const
{
    return sendFrame(io, FrameGoaway, 0);
}

int ProtocolHttp2::sendSettings(QIODevice *io, const std::vector<std::pair<quint16, quint32>> &settings) const
{
    Q_UNUSED(settings);
    return sendFrame(io, FrameSettings, 0);
}

int ProtocolHttp2::sendSettingsAck(QIODevice *io) const
{
    return sendFrame(io, FrameSettings, FlagSettingsAck);
}

int ProtocolHttp2::sendPing(QIODevice *io, quint8 flags, const char *data, qint32 dataLen) const
{
    return sendFrame(io, FramePing, flags, data, dataLen);
}

int ProtocolHttp2::sendFrame(QIODevice *io, quint8 type, quint8 flags, const char *data, qint32 dataLen) const
{
    h2_frame fr;

    fr.size2 = quint8(dataLen >> 16);
    fr.size1 = quint8(dataLen >> 8);
    fr.size0 = quint8(dataLen);
    fr.type = type;
    fr.flags = flags;
    fr.rbit_stream_id3 = 0;
    fr.rbit_stream_id2 = 0;
    fr.rbit_stream_id1 = 0;
    fr.rbit_stream_id0 = 0;

    qCDebug(CWSGI_H2) << "Sending frame"
                      << type
                      << flags
                      << quint32(fr.size0 | (fr.size1 << 8) | (fr.size2 << 16))
                      << quint32(fr.rbit_stream_id0 | (fr.rbit_stream_id1 << 8) | (fr.rbit_stream_id2 << 16) | (fr.rbit_stream_id3 << 24));

    qCDebug(CWSGI_H2) << "Frame" << QByteArray(reinterpret_cast<const char *>(&fr), sizeof(struct h2_frame));
    if (io->write(reinterpret_cast<const char *>(&fr), sizeof(struct h2_frame)) != sizeof(struct h2_frame)) {
        return -1;
    }
    if (dataLen && io->write(data, dataLen) != dataLen) {
        return -1;
    }
    return 0;
}

bool ProtocolHttp2::sendHeaders(QIODevice *io, Socket *sock, quint16 status, const QByteArray &dateHeader, const Cutelyst::Headers &headers)
{
    return false;
}
<commit_msg>Add some checks<commit_after>/*
 * Copyright (C) 2018 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "protocolhttp2.h"

#include "socket.h"

#include <QLoggingCategory>

using namespace CWSGI;

Q_LOGGING_CATEGORY(CWSGI_H2, "cwsgi.http2")

#ifdef Q_CC_MSVC
#pragma pack(push)
#pragma pack(1)
#endif
struct h2_frame {
    quint8 size2;
    quint8 size1;
    quint8 size0;
    quint8 type;
    quint8 flags;
    quint8 rbit_stream_id3;
    quint8 rbit_stream_id2;
    quint8 rbit_stream_id1;
    quint8 rbit_stream_id0;
}
#ifdef Q_CC_MSVC
;
#pragma pack(pop)
#else
__attribute__ ((__packed__));
#endif

enum Flags {
    FlagSettingsAck = 0x1,
    FlagPingAck = 0x1
};

enum FrameType {
    FrameData = 0x0,
    FrameHeaders = 0x1,
    FramePriority = 0x2,
    FrameRstStream = 0x3,
    FrameSettings = 0x4,
    FramePushPromise = 0x5,
    FramePing = 0x6,
    FrameGoaway = 0x7,
    FrameWindowUpdate = 0x8,
    FrameContinuation = 0x9
};

enum ErrorCodes {
    ErrorNoError = 0x0,
    ErrorProtocolError = 0x1,
    ErrorInternalError = 0x2,
    ErrorFlowControlError = 0x3,
    ErrorSettingsTimeout = 0x4,
    ErrorStreamClosed = 0x5,
    ErrorFrameSizeError = 0x6,
    ErrorRefusedStream = 0x7,
    ErrorCancel = 0x8,
    ErrorCompressionError = 0x9,
    ErrorConnectError = 0xA,
    ErrorEnhanceYourCalm  = 0xB,
    ErrorInadequateSecurity = 0xC,
    ErrorHttp11Required = 0xD
};

enum Settings {
    SETTINGS_HEADER_TABLE_SIZE = 0x1,
    SETTINGS_ENABLE_PUSH = 0x2,
    SETTINGS_MAX_CONCURRENT_STREAMS = 0x3,
    SETTINGS_INITIAL_WINDOW_SIZE = 0x4,
    SETTINGS_MAX_FRAME_SIZE = 0x5,
    SETTINGS_MAX_HEADER_LIST_SIZE = 0x6
};

quint32 h2_be32(const char *buf) {
    const quint32 *src = reinterpret_cast<const quint32 *>(buf);
    quint32 ret = 0;
    quint8 *ptr = reinterpret_cast<quint8 *>(&ret);
    ptr[0] = static_cast<quint8>((*src >> 24) & 0xff);
    ptr[1] = static_cast<quint8>((*src >> 16) & 0xff);
    ptr[2] = static_cast<quint8>((*src >> 8) & 0xff);
    ptr[3] = static_cast<quint8>(*src & 0xff);
    return ret;
}

quint32 h2_be24(const char *buf) {
    const quint32 *src = reinterpret_cast<const quint32 *>(buf);
    quint32 ret = 0;
    quint8 *ptr = reinterpret_cast<quint8 *>(&ret);
    ptr[0] = static_cast<quint8>((*src >> 16) & 0xff);
    ptr[1] = static_cast<quint8>((*src >> 8) & 0xff);
    ptr[2] = static_cast<quint8>(*src & 0xff);
    return ret;
}

quint16 h2_be16(const char *buf) {
    const quint32 *src = reinterpret_cast<const quint32 *>(buf);
    quint16 ret = 0;
    quint8 *ptr = reinterpret_cast<quint8 *>(&ret);
    ptr[0] = static_cast<quint8>((*src >> 8) & 0xff);
    ptr[1] = static_cast<quint8>(*src & 0xff);
    return ret;
}

#define PREFACE_SIZE 24

ProtocolHttp2::ProtocolHttp2(WSGI *wsgi) : Protocol(wsgi)
{

}

ProtocolHttp2::~ProtocolHttp2()
{

}

Protocol::Type ProtocolHttp2::type() const
{
    return Http2;
}

void ProtocolHttp2::readyRead(Socket *sock, QIODevice *io) const
{
    qint64 bytesAvailable = io->bytesAvailable();
    qCDebug(CWSGI_H2) << "readyRead available" << bytesAvailable;

    int len = io->read(sock->buffer + sock->buf_size, m_bufferSize - sock->buf_size);
    bytesAvailable -= len;

    if (len > 0) {
        sock->buf_size += len;

        while (sock->buf_size) {
            qDebug() << QByteArray(sock->buffer, sock->buf_size);
            if (sock->connState == Socket::MethodLine) {
                if (sock->buf_size >= PREFACE_SIZE) {
                    if (memcmp(sock->buffer, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", 24) == 0) {
                        qCDebug(CWSGI_H2) << "Got preface" << sizeof(struct h2_frame);
                        memmove(sock->buffer, sock->buffer + PREFACE_SIZE, sock->buf_size - PREFACE_SIZE);
                        sock->buf_size -= PREFACE_SIZE;
                        sock->connState = Socket::H2Frames;

                        std::vector<std::pair<quint16, quint32>> settings;
                        sendSettings(io, settings);
                    } else {
                        qCDebug(CWSGI_H2) << "Wrong preface";
                        sendError(io);
                        sock->connectionClose();
                        return;
                        //                    return PROTOCOL_ERROR;
                    }
                }
            } else if (sock->connState == Socket::H2Frames) {
                if (sock->buf_size >= sizeof(struct h2_frame)) {
                    auto fr = reinterpret_cast<struct h2_frame *>(sock->buffer);
                    sock->pktsize = fr->size0 | (fr->size1 << 8) | (fr->size2 << 16);
                    sock->stream_id = fr->rbit_stream_id0 |
                            (fr->rbit_stream_id1 << 8) |
                            (fr->rbit_stream_id2 << 16) |
                            ((fr->rbit_stream_id3 & ~0x80) << 24); // Ignore first bit

                    qDebug() << "frame type" << fr->type << "flags" << fr->flags << "stream-id" << sock->stream_id;
                    qDebug() << "Reserved bit" << (fr->rbit_stream_id3) << (fr->rbit_stream_id3 & ~0x80) << (fr->rbit_stream_id3 & 0x80);
//                    qDebug() << "frame size" << quint32(fr->size1 | (fr->size2 << 8) | (fr->size3 << 16));
                    qDebug() << "frame size" << sock->pktsize << "available" << (sock->buf_size - sizeof(struct h2_frame));
                    if (sock->pktsize > (sock->buf_size - sizeof(struct h2_frame))) {
                        qDebug() << "need more data" << bytesAvailable;
                        return;
                    }

                    if (fr->type == FrameSettings) {
                        qDebug() << "Consumming settings";
                        if ((fr->flags & FlagSettingsAck && sock->pktsize) || sock->pktsize % 6) {
                            // FRAME_SIZE_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        } else if (sock->stream_id) {
                            // PROTOCOL_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        QVector<std::pair<quint16, quint32>> settings;
                        uint pos = 0;
                        while (sock->pktsize > pos) {
                            quint16 identifier = h2_be16(sock->buffer + 9 + pos);
                            quint32 value = h2_be32(sock->buffer + 9 + 2 + pos);
                            settings.push_back({ identifier, value });
//                            sock->pktsize -= 6;
                            pos += 6;
                            if (identifier == SETTINGS_ENABLE_PUSH && value > 1) {
                                // PROTOCOL_ERROR
                                sendError(io);
                                sock->connectionClose();
                                return;
                            }
                            qDebug() << "SETTINGS" << identifier << value;
                        }
                        sendSettingsAck(io);

                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FramePriority) {
                        qDebug() << "Consumming priority";
                        if (sock->pktsize != 5) {
                            // FRAME_SIZE_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        uint pos = 0;
                        while (sock->pktsize > pos) {
                            // TODO store/disable EXCLUSIVE bit
                            quint32 exclusiveAndStreamDep = h2_be32(sock->buffer + 9 + pos);
                            quint8 weigth = *reinterpret_cast<quint8 *>(sock->buffer + 9 + 4 + pos) + 1;
//                            settings.push_back({ identifier, value });
//                            sock->pktsize -= 6;

                            if (exclusiveAndStreamDep == 0 || sock->stream_id == exclusiveAndStreamDep) {
                                // PROTOCOL_ERROR
                                sendError(io);
                                sock->connectionClose();
                                return;
                            }

                            pos += 6;
                            qDebug() << "PRIO" << exclusiveAndStreamDep << weigth;
                        }
                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FrameHeaders) {
                        qDebug() << "Consumming headers";
                        if (sock->stream_id == 0) {
                            // PROTOCOL_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FramePing) {
                        qCDebug(CWSGI_H2) << "Got ping" << fr->flags;
                        if (sock->pktsize != 8) {
                            // FRAME_SIZE_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        } else if (sock->stream_id) {
                            // PROTOCOL_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        if (!(fr->flags & FlagPingAck)) {
                            sendPing(io, FlagPingAck, sock->buffer + 9, 8);
                        }
                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FrameData) {
                        qCDebug(CWSGI_H2) << "Frame data" << fr->type;
                        if (sock->stream_id == 0) {
                            // PROTOCOL_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FramePushPromise) {
                        // PROTOCOL_ERROR
                        sendError(io);
                        sock->connectionClose();
                        return;
                    } else if (fr->type == FrameRstStream) {
                        if (sock->stream_id == 0) {
                            // PROTOCOL_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        } else if (sock->pktsize != 4) {
                            // FRAME_SIZE_ERROR
                            sendError(io);
                            sock->connectionClose();
                            return;
                        }

                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    } else if (fr->type == FrameGoaway) {
                        sock->connectionClose();
                        return;
                    } else {
                        qCDebug(CWSGI_H2) << "Unknown frame type" << fr->type;
                        // Implementations MUST ignore and discard any frame that has a type that is unknown.
                        sock->buf_size -= 9 + sock->pktsize;
                        memmove(sock->buffer, sock->buffer + 9 + sock->pktsize, sock->buf_size);
                    }
                }
            }
        }
    }
}

int ProtocolHttp2::sendError(QIODevice *io) const
{
    return sendFrame(io, FrameGoaway, 0);
}

int ProtocolHttp2::sendSettings(QIODevice *io, const std::vector<std::pair<quint16, quint32>> &settings) const
{
    Q_UNUSED(settings);
    return sendFrame(io, FrameSettings, 0);
}

int ProtocolHttp2::sendSettingsAck(QIODevice *io) const
{
    return sendFrame(io, FrameSettings, FlagSettingsAck);
}

int ProtocolHttp2::sendPing(QIODevice *io, quint8 flags, const char *data, qint32 dataLen) const
{
    return sendFrame(io, FramePing, flags, data, dataLen);
}

int ProtocolHttp2::sendFrame(QIODevice *io, quint8 type, quint8 flags, const char *data, qint32 dataLen) const
{
    h2_frame fr;

    fr.size2 = quint8(dataLen >> 16);
    fr.size1 = quint8(dataLen >> 8);
    fr.size0 = quint8(dataLen);
    fr.type = type;
    fr.flags = flags;
    fr.rbit_stream_id3 = 0;
    fr.rbit_stream_id2 = 0;
    fr.rbit_stream_id1 = 0;
    fr.rbit_stream_id0 = 0;

    qCDebug(CWSGI_H2) << "Sending frame"
                      << type
                      << flags
                      << quint32(fr.size0 | (fr.size1 << 8) | (fr.size2 << 16))
                      << quint32(fr.rbit_stream_id0 | (fr.rbit_stream_id1 << 8) | (fr.rbit_stream_id2 << 16) | (fr.rbit_stream_id3 << 24));

    qCDebug(CWSGI_H2) << "Frame" << QByteArray(reinterpret_cast<const char *>(&fr), sizeof(struct h2_frame));
    if (io->write(reinterpret_cast<const char *>(&fr), sizeof(struct h2_frame)) != sizeof(struct h2_frame)) {
        return -1;
    }
    if (dataLen && io->write(data, dataLen) != dataLen) {
        return -1;
    }
    return 0;
}

bool ProtocolHttp2::sendHeaders(QIODevice *io, Socket *sock, quint16 status, const QByteArray &dateHeader, const Cutelyst::Headers &headers)
{
    return false;
}
<|endoftext|>


<commit_before>#include "chr/gl/State.h"

namespace chr
{
  namespace gl
  {
    int State::usageCounter = 0;

    namespace state
    {
      State current;
    }

      State::State()
    :
    id(usageCounter++),
    element(new state::Element())
    {
      element->useCount++;
    }

    State::State(const State &other)
    :
    id(other.id),
    element(other.element)
    {
      element->useCount++;
    }

    State& State::operator=(const State &other)
    {
      if (this != &other)
      {
        id = other.id;
        element = other.element;

        element->useCount++;
      }

      return *this;
    }

    State::~State()
    {
      element->useCount--;

      if (element->useCount == 0)
      {
        delete element;
      }
    }

    State& State::setShader(const ShaderProgram &shader)
    {
      element->shader = shader;
      element->hasShader = true;
      return *this;
    }

    State& State::setShaderColor(const glm::vec4 &color)
    {
      element->color = color;
      element->hasColor = true;
      return *this;
    }

    State& State::setShaderColor(float r, float g, float b, float a)
    {
      element->color = { r, g, b, a };
      element->hasColor = true;
      return *this;
    }

    // ---

    State& State::glEnable(GLenum cap)
    {
      element->enabled[cap] = {true};
      return *this;
    }

    State& State::glDisable(GLenum cap)
    {
      element->enabled[cap] = {false};
      return *this;
    }

    State& State::glDepthMask(bool flag)
    {
      element->propui[PROPERTY_GL_DEPTH_MASK] = {flag};
      return *this;
    }

    State& State::glDepthFunc(GLenum func)
    {
      element->propui[PROPERTY_GL_DEPTH_FUNC] = {func};
      return *this;
    }

    State& State::glBlendFunc(GLenum sfactor, GLenum dfactor)
    {
      element->propui[PROPERTY_GL_BLEND_FUNC] = {sfactor, dfactor};
      return *this;
    }

    State& State::glCullFace(GLenum mode)
    {
      element->propui[PROPERTY_GL_CULL_FACE] = {mode};
      return *this;
    }

    State& State::glFrontFace(GLenum mode)
    {
      element->propui[PROPERTY_GL_FRONT_FACE] = {mode};
      return *this;
    }

    State& State::glLineWidth(float width)
    {
      element->propf[PROPERTY_GL_LINE_WIDTH] = {width};
      return *this;
    }

    State& State::glPointSize(float size)
    {
      element->propf[PROPERTY_GL_POINT_SIZE] = {size};
      return *this;
    }

    State& State::glPolygonOffset(GLfloat factor, GLfloat units)
    {
      element->propf[PROPERTY_GL_POLYGON_OFFSET] = {factor, units};
      return *this;
    }

    // ---

    void State::apply()
    {
      if (element->hasShader)
      {
        element->shader.bind();
        apply(element->shader);
      }

      for (auto it = element->enabled.begin(); it != element->enabled.end(); ++it)
      {
        if (it->second)
        {
          ::glEnable(it->first);
        }
        else
        {
          ::glDisable(it->first);
        }
      }

      for (auto it = element->propui.begin(); it != element->propui.end(); ++it)
      {
        switch (it->first)
        {
          case PROPERTY_GL_DEPTH_MASK:
            ::glDepthMask(it->second[0]);
            break;

          case PROPERTY_GL_DEPTH_FUNC:
            ::glDepthFunc(it->second[0]);
            break;

          case PROPERTY_GL_BLEND_FUNC:
            ::glBlendFunc(it->second[0], it->second[1]);
            break;

          case PROPERTY_GL_CULL_FACE:
            ::glCullFace(it->second[0]);
            break;

          case PROPERTY_GL_FRONT_FACE:
            ::glFrontFace(it->second[0]);
            break;
        }
      }

      for (auto it = element->propf.begin(); it != element->propf.end(); ++it)
      {
        switch (it->first)
        {
          case PROPERTY_GL_POLYGON_OFFSET:
            ::glPolygonOffset(it->second[0], it->second[1]);
            break;

          case PROPERTY_GL_LINE_WIDTH:
            ::glLineWidth(it->second[0]);
            break;

          case PROPERTY_GL_POINT_SIZE:
            #ifdef CHR_PLATFORM_DESKTOP
              ::glPointSize(it->second[0]);
            #endif
            break;
        }
      }

      state::current = *this;
    }

    void State::apply(ShaderProgram &shader)
    {
      if (element->hasColor)
      {
        shader.applyColor(element->color);
      }

      if (element->hasMatrix4[MV])
      {
        shader.applyMatrix<MV>(element->matrices4[MV]);
      }

      if (element->hasMatrix4[MVP])
      {
        shader.applyMatrix<MVP>(element->matrices4[MVP]);
      }

      if (element->hasMatrix4[PROJECTION])
      {
        shader.applyMatrix<PROJECTION>(element->matrices4[PROJECTION]);
      }

      if (element->hasMatrix3[NORMAL])
      {
        shader.applyMatrix<NORMAL>(element->matrices3[NORMAL]);
      }

      for (auto it = element->uniformi.begin(); it != element->uniformi.end(); ++it)
      {
        shader.applyUniform(it->first, it->second);
      }

      for (auto it = element->uniformf.begin(); it != element->uniformf.end(); ++it)
      {
        shader.applyUniform(it->first, it->second);
      }

      for (auto it = element->uniformm3.begin(); it != element->uniformm3.end(); ++it)
      {
        shader.applyUniform(it->first, it->second);
      }

      for (auto it = element->uniformm4.begin(); it != element->uniformm4.end(); ++it)
      {
        shader.applyUniform(it->first, it->second);
      }
    }
  }
}
<commit_msg>core: Fixing memory-leak + cosmetics<commit_after>#include "chr/gl/State.h"

namespace chr
{
  namespace gl
  {
    int State::usageCounter = 0;

    namespace state
    {
      State current;
    }

    State::State()
    :
    id(usageCounter++),
    element(new state::Element())
    {
      element->useCount++;
    }

    State::State(const State &other)
    :
    id(other.id),
    element(other.element)
    {
      element->useCount++;
    }

    State& State::operator=(const State &other)
    {
      if (this != &other)
      {
        id = other.id;
        element = other.element;

        element->useCount++;
      }

      return *this;
    }

    State::~State()
    {
      if (--element->useCount == 0)
      {
        delete element;
      }
    }

    State& State::setShader(const ShaderProgram &shader)
    {
      element->shader = shader;
      element->hasShader = true;
      return *this;
    }

    State& State::setShaderColor(const glm::vec4 &color)
    {
      element->color = color;
      element->hasColor = true;
      return *this;
    }

    State& State::setShaderColor(float r, float g, float b, float a)
    {
      element->color = { r, g, b, a };
      element->hasColor = true;
      return *this;
    }

    // ---

    State& State::glEnable(GLenum cap)
    {
      element->enabled[cap] = {true};
      return *this;
    }

    State& State::glDisable(GLenum cap)
    {
      element->enabled[cap] = {false};
      return *this;
    }

    State& State::glDepthMask(bool flag)
    {
      element->propui[PROPERTY_GL_DEPTH_MASK] = {flag};
      return *this;
    }

    State& State::glDepthFunc(GLenum func)
    {
      element->propui[PROPERTY_GL_DEPTH_FUNC] = {func};
      return *this;
    }

    State& State::glBlendFunc(GLenum sfactor, GLenum dfactor)
    {
      element->propui[PROPERTY_GL_BLEND_FUNC] = {sfactor, dfactor};
      return *this;
    }

    State& State::glCullFace(GLenum mode)
    {
      element->propui[PROPERTY_GL_CULL_FACE] = {mode};
      return *this;
    }

    State& State::glFrontFace(GLenum mode)
    {
      element->propui[PROPERTY_GL_FRONT_FACE] = {mode};
      return *this;
    }

    State& State::glLineWidth(float width)
    {
      element->propf[PROPERTY_GL_LINE_WIDTH] = {width};
      return *this;
    }

    State& State::glPointSize(float size)
    {
      element->propf[PROPERTY_GL_POINT_SIZE] = {size};
      return *this;
    }

    State& State::glPolygonOffset(GLfloat factor, GLfloat units)
    {
      element->propf[PROPERTY_GL_POLYGON_OFFSET] = {factor, units};
      return *this;
    }

    // ---

    void State::apply()
    {
      if (element->hasShader)
      {
        element->shader.bind();
        apply(element->shader);
      }

      for (auto it = element->enabled.begin(); it != element->enabled.end(); ++it)
      {
        if (it->second)
        {
          ::glEnable(it->first);
        }
        else
        {
          ::glDisable(it->first);
        }
      }

      for (auto it = element->propui.begin(); it != element->propui.end(); ++it)
      {
        switch (it->first)
        {
          case PROPERTY_GL_DEPTH_MASK:
            ::glDepthMask(it->second[0]);
            break;

          case PROPERTY_GL_DEPTH_FUNC:
            ::glDepthFunc(it->second[0]);
            break;

          case PROPERTY_GL_BLEND_FUNC:
            ::glBlendFunc(it->second[0], it->second[1]);
            break;

          case PROPERTY_GL_CULL_FACE:
            ::glCullFace(it->second[0]);
            break;

          case PROPERTY_GL_FRONT_FACE:
            ::glFrontFace(it->second[0]);
            break;
        }
      }

      for (auto it = element->propf.begin(); it != element->propf.end(); ++it)
      {
        switch (it->first)
        {
          case PROPERTY_GL_POLYGON_OFFSET:
            ::glPolygonOffset(it->second[0], it->second[1]);
            break;

          case PROPERTY_GL_LINE_WIDTH:
            ::glLineWidth(it->second[0]);
            break;

          case PROPERTY_GL_POINT_SIZE:
            #ifdef CHR_PLATFORM_DESKTOP
              ::glPointSize(it->second[0]);
            #endif
            break;
        }
      }

      if (--state::current->useCount == 0)
      {
        delete state::current.element;
      }

      state::current = *this;
    }

    void State::apply(ShaderProgram &shader)
    {
      if (element->hasColor)
      {
        shader.applyColor(element->color);
      }

      if (element->hasMatrix4[MV])
      {
        shader.applyMatrix<MV>(element->matrices4[MV]);
      }

      if (element->hasMatrix4[MVP])
      {
        shader.applyMatrix<MVP>(element->matrices4[MVP]);
      }

      if (element->hasMatrix4[PROJECTION])
      {
        shader.applyMatrix<PROJECTION>(element->matrices4[PROJECTION]);
      }

      if (element->hasMatrix3[NORMAL])
      {
        shader.applyMatrix<NORMAL>(element->matrices3[NORMAL]);
      }

      for (auto it = element->uniformi.begin(); it != element->uniformi.end(); ++it)
      {
        shader.applyUniform(it->first, it->second);
      }

      for (auto it = element->uniformf.begin(); it != element->uniformf.end(); ++it)
      {
        shader.applyUniform(it->first, it->second);
      }

      for (auto it = element->uniformm3.begin(); it != element->uniformm3.end(); ++it)
      {
        shader.applyUniform(it->first, it->second);
      }

      for (auto it = element->uniformm4.begin(); it != element->uniformm4.end(); ++it)
      {
        shader.applyUniform(it->first, it->second);
      }
    }
  }
}
<|endoftext|>


<commit_before>#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <elf.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <stdlib.h>
#include <iostream>
#include <arpa/inet.h>
#include "system.h"
#include "Vtop_top.h"

using namespace std;

#ifndef be32toh
#define be32toh(x)      ((u_int32_t)ntohl((u_int32_t)(x)))
#endif

static __inline__ u_int64_t cse502_be64toh(u_int64_t __x) { return (((u_int64_t)be32toh(__x & (u_int64_t)0xFFFFFFFFULL)) << 32) | ((u_int64_t)be32toh((__x & (u_int64_t)0xFFFFFFFF00000000ULL) >> 32)); }

uint64_t System::load_elf(const char* filename) {
	int fd = open(filename,O_RDONLY);
	assert(fd != -1);
	Elf64_Ehdr ehdr;
	assert(read(fd,(void*)&ehdr,sizeof(ehdr))==sizeof(ehdr));
	Elf64_Phdr phdr[10];
	int phnum = ehdr.e_phnum;
	assert(phnum < (sizeof(phdr)/sizeof(Elf64_Phdr)));
	assert(lseek(fd,ehdr.e_phoff,SEEK_SET)!=-1);
	assert(read(fd,(void*)&phdr,sizeof(phdr))==sizeof(phdr));
	for(int header=0; header<phnum ; ++header) {
		Elf64_Phdr *p = &phdr[header];
		if (p->p_type == PT_LOAD) {
			if ((p->p_vaddr + p->p_memsz) > ramsize) {
				cerr << "Not enough 'physical' ram" << endl;
				exit(-1);
			}
			memset(ram+p->p_vaddr,0,p->p_memsz);
			assert(lseek(fd,p->p_offset,SEEK_SET)!=-1);
			assert(read(fd,(void*)(ram+p->p_vaddr),p->p_filesz)==p->p_filesz);
			//cerr << "section flags " << hex << p->p_flags << endl;
		} else if (p->p_type == PT_GNU_STACK) {
			// do nothing
		} else {
			cerr << "Unexpected ELF header " << p->p_type << endl;
			exit(-1);
		}
	}
	close(fd);
	return ehdr.e_entry;
}

void System::dram_read_complete(unsigned id, uint64_t address, uint64_t clock_cycle) {
	std::map<uint64_t, int>::iterator tag = addr_to_tag.find(address);
	assert(tag != addr_to_tag.end());
	for(int i=0; i<64; i+=8) {
		//cerr << "fill data from " << std::hex << (address+(i&63)) <<  ": " << tx_queue.rbegin()->first << " on tag " << tag->second << endl;
		tx_queue.push_back(make_pair(cse502_be64toh(*((uint64_t*)(&ram[address+(i&63)]))),tag->second));
	}
	addr_to_tag.erase(tag);
}

void System::dram_write_complete(unsigned id, uint64_t address, uint64_t clock_cycle) {
}

System::System(Vtop* top, uint64_t ramsize, const char* ramelf, int ps_per_clock)
:	top(top)
,	ramsize(ramsize)
{
	ram = (char*)malloc(ramsize);
	assert(ram);
	if (ramelf) top->entry = load_elf(ramelf);

	dramsim = DRAMSim::getMemorySystemInstance("DDR2_micron_16M_8b_x8_sg3E.ini", "system.ini", "../dramsim2", "dram_result", ramsize/M);
	DRAMSim::TransactionCompleteCB *read_cb = new DRAMSim::Callback<System, void, unsigned, uint64_t, uint64_t>(this, &System::dram_read_complete);
	DRAMSim::TransactionCompleteCB *write_cb = new DRAMSim::Callback<System, void, unsigned, uint64_t, uint64_t>(this, &System::dram_write_complete);
	dramsim->RegisterCallbacks(read_cb, NULL, NULL);
	dramsim->setCPUClockSpeed(1000ULL/ps_per_clock*1000*1000*1000);
}

System::~System() {
	free(ram);
}

enum {
	READ   = 0b1,
	WRITE  = 0b0,
	MEMORY = 0b0001,
	MMIO   = 0b0011,
	PORT   = 0b0100,
	IRQ    = 0b1110
};

void System::tick(int clk) {
	if (!clk) {
		if (top->reqcyc) {
			top->reqack = dramsim->willAcceptTransaction(); // hack: blocks ACK if /any/ memory channel can't accept transaction
			assert(!rx_count || top->reqack); // if trnasfer is in progress, can't change mind about willAcceptTransaction()
		}
		return;
	}

	dramsim->update();
	if (!tx_queue.empty() && top->respack) tx_queue.pop_front();
	if (!tx_queue.empty()) {
		top->respcyc = 1;
		top->resp = tx_queue.begin()->first;
		top->resptag = tx_queue.begin()->second;
		//cerr << "responding data " << top->resp << " on tag " << std::hex << top->resptag << endl;
	} else {
		top->respcyc = 0;
		top->resp = 0xaaaaaaaaaaaaaaaaULL;
		top->resptag = 0xaaaa;
	}

	if (rx_count) --rx_count;
	if (top->reqcyc) {
		if (rx_count) return;
		bool isWrite = ((top->reqtag >> 12) & 1) == WRITE;
		cmd = (top->reqtag >> 8) & 0xf;
		if (cmd == MEMORY && isWrite) rx_count = 8;
		if (cmd == MMIO) rx_count = 1;
		else rx_count = 0;
		uint64_t xfer_addr;
		switch(cmd) {
		case MEMORY:
 			xfer_addr = top->req;
			assert(!(xfer_addr & 7));
			assert(
				dramsim->addTransaction(isWrite, xfer_addr)
			);
			//cerr << "add transaction " << std::hex << xfer_addr << " on tag " << top->reqtag << endl;
			if (!isWrite) addr_to_tag[xfer_addr] = top->reqtag;
			break;
		default:
			assert(0);
		};
	} else {
		top->reqack = 0;
		rx_count = 0;
	}
}
<commit_msg>Ignoring section NOTE (0x4) in the ELF header.<commit_after>#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <elf.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <stdlib.h>
#include <iostream>
#include <arpa/inet.h>
#include "system.h"
#include "Vtop_top.h"

using namespace std;

#ifndef be32toh
#define be32toh(x)      ((u_int32_t)ntohl((u_int32_t)(x)))
#endif

static __inline__ u_int64_t cse502_be64toh(u_int64_t __x) { return (((u_int64_t)be32toh(__x & (u_int64_t)0xFFFFFFFFULL)) << 32) | ((u_int64_t)be32toh((__x & (u_int64_t)0xFFFFFFFF00000000ULL) >> 32)); }

uint64_t System::load_elf(const char* filename) {
	int fd = open(filename,O_RDONLY);
	assert(fd != -1);
	Elf64_Ehdr ehdr;
	assert(read(fd,(void*)&ehdr,sizeof(ehdr))==sizeof(ehdr));
	Elf64_Phdr phdr[10];
	int phnum = ehdr.e_phnum;
	assert(phnum < (sizeof(phdr)/sizeof(Elf64_Phdr)));
	assert(lseek(fd,ehdr.e_phoff,SEEK_SET)!=-1);
	assert(read(fd,(void*)&phdr,sizeof(phdr))==sizeof(phdr));
	for(int header=0; header<phnum ; ++header) {
		Elf64_Phdr *p = &phdr[header];
		if (p->p_type == PT_LOAD) {
			if ((p->p_vaddr + p->p_memsz) > ramsize) {
				cerr << "Not enough 'physical' ram" << endl;
				exit(-1);
			}
			memset(ram+p->p_vaddr,0,p->p_memsz);
			assert(lseek(fd,p->p_offset,SEEK_SET)!=-1);
			assert(read(fd,(void*)(ram+p->p_vaddr),p->p_filesz)==p->p_filesz);
			//cerr << "section flags " << hex << p->p_flags << endl;
		} else if (p->p_type == PT_GNU_STACK) {
			// do nothing
		} else if (p->p_type == 0x4) {
			// do nothing
		} else {
			cerr << "Unexpected ELF header " << p->p_type << endl;
			exit(-1);
		}
	}
	close(fd);
	return ehdr.e_entry;
}

void System::dram_read_complete(unsigned id, uint64_t address, uint64_t clock_cycle) {
	std::map<uint64_t, int>::iterator tag = addr_to_tag.find(address);
	assert(tag != addr_to_tag.end());
	for(int i=0; i<64; i+=8) {
		//cerr << "fill data from " << std::hex << (address+(i&63)) <<  ": " << tx_queue.rbegin()->first << " on tag " << tag->second << endl;
		tx_queue.push_back(make_pair(cse502_be64toh(*((uint64_t*)(&ram[address+(i&63)]))),tag->second));
	}
	addr_to_tag.erase(tag);
}

void System::dram_write_complete(unsigned id, uint64_t address, uint64_t clock_cycle) {
}

System::System(Vtop* top, uint64_t ramsize, const char* ramelf, int ps_per_clock)
:	top(top)
,	ramsize(ramsize)
{
	ram = (char*)malloc(ramsize);
	assert(ram);
	if (ramelf) top->entry = load_elf(ramelf);

	dramsim = DRAMSim::getMemorySystemInstance("DDR2_micron_16M_8b_x8_sg3E.ini", "system.ini", "../dramsim2", "dram_result", ramsize/M);
	DRAMSim::TransactionCompleteCB *read_cb = new DRAMSim::Callback<System, void, unsigned, uint64_t, uint64_t>(this, &System::dram_read_complete);
	DRAMSim::TransactionCompleteCB *write_cb = new DRAMSim::Callback<System, void, unsigned, uint64_t, uint64_t>(this, &System::dram_write_complete);
	dramsim->RegisterCallbacks(read_cb, NULL, NULL);
	dramsim->setCPUClockSpeed(1000ULL/ps_per_clock*1000*1000*1000);
}

System::~System() {
	free(ram);
}

enum {
	READ   = 0b1,
	WRITE  = 0b0,
	MEMORY = 0b0001,
	MMIO   = 0b0011,
	PORT   = 0b0100,
	IRQ    = 0b1110
};

void System::tick(int clk) {
	if (!clk) {
		if (top->reqcyc) {
			top->reqack = dramsim->willAcceptTransaction(); // hack: blocks ACK if /any/ memory channel can't accept transaction
			assert(!rx_count || top->reqack); // if trnasfer is in progress, can't change mind about willAcceptTransaction()
		}
		return;
	}

	dramsim->update();
	if (!tx_queue.empty() && top->respack) tx_queue.pop_front();
	if (!tx_queue.empty()) {
		top->respcyc = 1;
		top->resp = tx_queue.begin()->first;
		top->resptag = tx_queue.begin()->second;
		//cerr << "responding data " << top->resp << " on tag " << std::hex << top->resptag << endl;
	} else {
		top->respcyc = 0;
		top->resp = 0xaaaaaaaaaaaaaaaaULL;
		top->resptag = 0xaaaa;
	}

	if (rx_count) --rx_count;
	if (top->reqcyc) {
		if (rx_count) return;
		bool isWrite = ((top->reqtag >> 12) & 1) == WRITE;
		cmd = (top->reqtag >> 8) & 0xf;
		if (cmd == MEMORY && isWrite) rx_count = 8;
		if (cmd == MMIO) rx_count = 1;
		else rx_count = 0;
		uint64_t xfer_addr;
		switch(cmd) {
		case MEMORY:
 			xfer_addr = top->req;
			assert(!(xfer_addr & 7));
			assert(
				dramsim->addTransaction(isWrite, xfer_addr)
			);
			//cerr << "add transaction " << std::hex << xfer_addr << " on tag " << top->reqtag << endl;
			if (!isWrite) addr_to_tag[xfer_addr] = top->reqtag;
			break;
		default:
			assert(0);
		};
	} else {
		top->reqack = 0;
		rx_count = 0;
	}
}
<|endoftext|>