<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xsecparser.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: ihi $ $Date: 2008-02-04 13:43:11 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmlsecurity.hxx"

#include "xsecparser.hxx"

#ifndef _TOOLS_DEBUG_HXX //autogen wg. DBG_ASSERT
#include <tools/debug.hxx>
#endif
#include "cppuhelper/exc_hlp.hxx"

#include <string.h>

namespace cssu = com::sun::star::uno;
namespace cssxs = com::sun::star::xml::sax;

#define RTL_ASCII_USTRINGPARAM( asciiStr ) asciiStr, strlen( asciiStr ), RTL_TEXTENCODING_ASCII_US

XSecParser::XSecParser(
    XSecController* pXSecController,
    const cssu::Reference< cssxs::XDocumentHandler >& xNextHandler )
    : m_pXSecController(pXSecController),
      m_xNextHandler(xNextHandler),
      m_bReferenceUnresolved(false)
{
}

rtl::OUString XSecParser::getIdAttr(const cssu::Reference< cssxs::XAttributeList >& xAttribs )
{
    rtl::OUString ouIdAttr = xAttribs->getValueByName(
        rtl::OUString(RTL_ASCII_USTRINGPARAM("id")));

    if (ouIdAttr == NULL)
    {
        ouIdAttr = xAttribs->getValueByName(
            rtl::OUString(RTL_ASCII_USTRINGPARAM("Id")));
    }

    return ouIdAttr;
}

/*
 * XDocumentHandler
 */
void SAL_CALL XSecParser::startDocument(  )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    m_bInX509IssuerName = false;
    m_bInX509SerialNumber = false;
    m_bInX509Certificate = false;
    m_bInSignatureValue = false;
    m_bInDigestValue = false;
    m_bInDate = false;
    //m_bInTime = false;

    if (m_xNextHandler.is())
    {
        m_xNextHandler->startDocument();
    }
}

void SAL_CALL XSecParser::endDocument(  )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_xNextHandler.is())
    {
        m_xNextHandler->endDocument();
    }
}

void SAL_CALL XSecParser::startElement(
    const rtl::OUString& aName,
    const cssu::Reference< cssxs::XAttributeList >& xAttribs )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    try
    {
        rtl::OUString ouIdAttr = getIdAttr(xAttribs);
        if (ouIdAttr != NULL)
        {
            m_pXSecController->collectToVerify( ouIdAttr );
        }

        if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNATURE)) )
        {
            m_pXSecController->addSignature();
            if (ouIdAttr != NULL)
            {
                m_pXSecController->setId( ouIdAttr );
            }
        }
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_REFERENCE)) )
        {
            rtl::OUString ouUri = xAttribs->getValueByName(rtl::OUString(RTL_ASCII_USTRINGPARAM(ATTR_URI)));
            DBG_ASSERT( ouUri != NULL, "URI == NULL" );

            if (0 == ouUri.compareTo(rtl::OUString(RTL_ASCII_USTRINGPARAM(CHAR_FRAGMENT)),1))
            {
                /*
                * remove the first character '#' from the attribute value
                */
                m_pXSecController->addReference( ouUri.copy(1) );
            }
            else
            {
                /*
                * remember the uri
                */
                m_currentReferenceURI = ouUri;
                m_bReferenceUnresolved = true;
            }
        }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_TRANSFORM)))
            {
            if ( m_bReferenceUnresolved )
            {
                rtl::OUString ouAlgorithm = xAttribs->getValueByName(rtl::OUString(RTL_ASCII_USTRINGPARAM(ATTR_ALGORITHM)));

                if (ouAlgorithm != NULL && ouAlgorithm == rtl::OUString(RTL_ASCII_USTRINGPARAM(ALGO_C14N)))
                /*
                * a xml stream
                */
                {
                    m_pXSecController->addStreamReference( m_currentReferenceURI, sal_False);
                    m_bReferenceUnresolved = false;
                }
            }
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509ISSUERNAME)))
            {
            m_ouX509IssuerName = rtl::OUString::createFromAscii("");
            m_bInX509IssuerName = true;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509SERIALNUMBER)))
            {
            m_ouX509SerialNumber = rtl::OUString::createFromAscii("");
            m_bInX509SerialNumber = true;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509CERTIFICATE)))
            {
            m_ouX509Certificate = rtl::OUString::createFromAscii("");
            m_bInX509Certificate = true;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNATUREVALUE)))
            {
            m_ouSignatureValue = rtl::OUString::createFromAscii("");
                m_bInSignatureValue = true;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_DIGESTVALUE)))
            {
            m_ouDigestValue = rtl::OUString::createFromAscii("");
                m_bInDigestValue = true;
            }
            else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNATUREPROPERTY)) )
        {
            if (ouIdAttr != NULL)
            {
                m_pXSecController->setPropertyId( ouIdAttr );
            }
        }
            else if (aName == rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(NSTAG_DC))
                        +rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":"))
                        +rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(TAG_DATE)))
            {
            m_ouDate = rtl::OUString::createFromAscii("");
                m_bInDate = true;
            }
            /*
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_TIME)))
            {
            m_ouTime = rtl::OUString::createFromAscii("");
                m_bInTime = true;
            }
            */

        if (m_xNextHandler.is())
        {
            m_xNextHandler->startElement(aName, xAttribs);
        }
    }
    catch (cssu::Exception& )
    {//getCaughtException MUST be the first line in the catch block
        cssu::Any exc =  cppu::getCaughtException();
        throw cssxs::SAXException(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
                              "xmlsecurity: Exception in XSecParser::startElement")),
            0, exc);
    }
    catch (...)
    {
        throw cssxs::SAXException(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xmlsecurity: unexpected exception in XSecParser::startElement")), 0,
            cssu::Any());
    }
}

void SAL_CALL XSecParser::endElement( const rtl::OUString& aName )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    try
    {
        if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_DIGESTVALUE)))
            {
                m_bInDigestValue = false;
            }
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_REFERENCE)) )
        {
            if ( m_bReferenceUnresolved )
            /*
            * it must be a octet stream
            */
            {
                m_pXSecController->addStreamReference( m_currentReferenceURI, sal_True);
                m_bReferenceUnresolved = false;
            }

            m_pXSecController->setDigestValue( m_ouDigestValue );
        }
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNEDINFO)) )
        {
            m_pXSecController->setReferenceCount();
        }
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNATUREVALUE)) )
        {
            m_pXSecController->setSignatureValue( m_ouSignatureValue );
                m_bInSignatureValue = false;
        }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509ISSUERNAME)))
            {
            m_pXSecController->setX509IssuerName( m_ouX509IssuerName );
            m_bInX509IssuerName = false;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509SERIALNUMBER)))
            {
            m_pXSecController->setX509SerialNumber( m_ouX509SerialNumber );
            m_bInX509SerialNumber = false;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509CERTIFICATE)))
            {
            m_pXSecController->setX509Certificate( m_ouX509Certificate );
            m_bInX509Certificate = false;
            }
            else if (aName == rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(NSTAG_DC))
                        +rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":"))
                        +rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(TAG_DATE)))
        {
            m_pXSecController->setDate( m_ouDate );
                m_bInDate = false;
        }
        /*
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_TIME)) )
        {
            m_pXSecController->setTime( m_ouTime );
                m_bInTime = false;
        }
        */

        if (m_xNextHandler.is())
        {
            m_xNextHandler->endElement(aName);
        }
    }
    catch (cssu::Exception& )
    {//getCaughtException MUST be the first line in the catch block
        cssu::Any exc =  cppu::getCaughtException();
        throw cssxs::SAXException(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
                              "xmlsecurity: Exception in XSecParser::endElement")),
            0, exc);
    }
    catch (...)
    {
        throw cssxs::SAXException(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xmlsecurity: unexpected exception in XSecParser::endElement")), 0,
            cssu::Any());
    }
}

void SAL_CALL XSecParser::characters( const rtl::OUString& aChars )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_bInX509IssuerName)
    {
        m_ouX509IssuerName += aChars;
    }
    else if (m_bInX509SerialNumber)
    {
        m_ouX509SerialNumber += aChars;
    }
    else if (m_bInX509Certificate)
    {
        m_ouX509Certificate += aChars;
    }
    else if (m_bInSignatureValue)
    {
        m_ouSignatureValue += aChars;
    }
    else if (m_bInDigestValue)
    {
        m_ouDigestValue += aChars;
    }
    else if (m_bInDate)
    {
        m_ouDate += aChars;
    }
    /*
    else if (m_bInTime)
    {
        m_ouTime += aChars;
    }
    */

    if (m_xNextHandler.is())
    {
        m_xNextHandler->characters(aChars);
        }
}

void SAL_CALL XSecParser::ignorableWhitespace( const rtl::OUString& aWhitespaces )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_xNextHandler.is())
    {
        m_xNextHandler->ignorableWhitespace( aWhitespaces );
        }
}

void SAL_CALL XSecParser::processingInstruction( const rtl::OUString& aTarget, const rtl::OUString& aData )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_xNextHandler.is())
    {
        m_xNextHandler->processingInstruction(aTarget, aData);
        }
}

void SAL_CALL XSecParser::setDocumentLocator( const cssu::Reference< cssxs::XLocator >& xLocator )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_xNextHandler.is())
    {
        m_xNextHandler->setDocumentLocator( xLocator );
        }
}

/*
 * XInitialization
 */
void SAL_CALL XSecParser::initialize(
    const cssu::Sequence< cssu::Any >& aArguments )
    throw(cssu::Exception, cssu::RuntimeException)
{
    aArguments[0] >>= m_xNextHandler;
}
<commit_msg>INTEGRATION: CWS changefileheader (1.7.10); FILE MERGED 2008/04/01 16:11:00 thb 1.7.10.2: #i85898# Stripping all external header guards 2008/03/31 16:31:02 rt 1.7.10.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: xsecparser.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmlsecurity.hxx"

#include "xsecparser.hxx"
#include <tools/debug.hxx>
#include "cppuhelper/exc_hlp.hxx"

#include <string.h>

namespace cssu = com::sun::star::uno;
namespace cssxs = com::sun::star::xml::sax;

#define RTL_ASCII_USTRINGPARAM( asciiStr ) asciiStr, strlen( asciiStr ), RTL_TEXTENCODING_ASCII_US

XSecParser::XSecParser(
    XSecController* pXSecController,
    const cssu::Reference< cssxs::XDocumentHandler >& xNextHandler )
    : m_pXSecController(pXSecController),
      m_xNextHandler(xNextHandler),
      m_bReferenceUnresolved(false)
{
}

rtl::OUString XSecParser::getIdAttr(const cssu::Reference< cssxs::XAttributeList >& xAttribs )
{
    rtl::OUString ouIdAttr = xAttribs->getValueByName(
        rtl::OUString(RTL_ASCII_USTRINGPARAM("id")));

    if (ouIdAttr == NULL)
    {
        ouIdAttr = xAttribs->getValueByName(
            rtl::OUString(RTL_ASCII_USTRINGPARAM("Id")));
    }

    return ouIdAttr;
}

/*
 * XDocumentHandler
 */
void SAL_CALL XSecParser::startDocument(  )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    m_bInX509IssuerName = false;
    m_bInX509SerialNumber = false;
    m_bInX509Certificate = false;
    m_bInSignatureValue = false;
    m_bInDigestValue = false;
    m_bInDate = false;
    //m_bInTime = false;

    if (m_xNextHandler.is())
    {
        m_xNextHandler->startDocument();
    }
}

void SAL_CALL XSecParser::endDocument(  )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_xNextHandler.is())
    {
        m_xNextHandler->endDocument();
    }
}

void SAL_CALL XSecParser::startElement(
    const rtl::OUString& aName,
    const cssu::Reference< cssxs::XAttributeList >& xAttribs )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    try
    {
        rtl::OUString ouIdAttr = getIdAttr(xAttribs);
        if (ouIdAttr != NULL)
        {
            m_pXSecController->collectToVerify( ouIdAttr );
        }

        if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNATURE)) )
        {
            m_pXSecController->addSignature();
            if (ouIdAttr != NULL)
            {
                m_pXSecController->setId( ouIdAttr );
            }
        }
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_REFERENCE)) )
        {
            rtl::OUString ouUri = xAttribs->getValueByName(rtl::OUString(RTL_ASCII_USTRINGPARAM(ATTR_URI)));
            DBG_ASSERT( ouUri != NULL, "URI == NULL" );

            if (0 == ouUri.compareTo(rtl::OUString(RTL_ASCII_USTRINGPARAM(CHAR_FRAGMENT)),1))
            {
                /*
                * remove the first character '#' from the attribute value
                */
                m_pXSecController->addReference( ouUri.copy(1) );
            }
            else
            {
                /*
                * remember the uri
                */
                m_currentReferenceURI = ouUri;
                m_bReferenceUnresolved = true;
            }
        }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_TRANSFORM)))
            {
            if ( m_bReferenceUnresolved )
            {
                rtl::OUString ouAlgorithm = xAttribs->getValueByName(rtl::OUString(RTL_ASCII_USTRINGPARAM(ATTR_ALGORITHM)));

                if (ouAlgorithm != NULL && ouAlgorithm == rtl::OUString(RTL_ASCII_USTRINGPARAM(ALGO_C14N)))
                /*
                * a xml stream
                */
                {
                    m_pXSecController->addStreamReference( m_currentReferenceURI, sal_False);
                    m_bReferenceUnresolved = false;
                }
            }
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509ISSUERNAME)))
            {
            m_ouX509IssuerName = rtl::OUString::createFromAscii("");
            m_bInX509IssuerName = true;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509SERIALNUMBER)))
            {
            m_ouX509SerialNumber = rtl::OUString::createFromAscii("");
            m_bInX509SerialNumber = true;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509CERTIFICATE)))
            {
            m_ouX509Certificate = rtl::OUString::createFromAscii("");
            m_bInX509Certificate = true;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNATUREVALUE)))
            {
            m_ouSignatureValue = rtl::OUString::createFromAscii("");
                m_bInSignatureValue = true;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_DIGESTVALUE)))
            {
            m_ouDigestValue = rtl::OUString::createFromAscii("");
                m_bInDigestValue = true;
            }
            else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNATUREPROPERTY)) )
        {
            if (ouIdAttr != NULL)
            {
                m_pXSecController->setPropertyId( ouIdAttr );
            }
        }
            else if (aName == rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(NSTAG_DC))
                        +rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":"))
                        +rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(TAG_DATE)))
            {
            m_ouDate = rtl::OUString::createFromAscii("");
                m_bInDate = true;
            }
            /*
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_TIME)))
            {
            m_ouTime = rtl::OUString::createFromAscii("");
                m_bInTime = true;
            }
            */

        if (m_xNextHandler.is())
        {
            m_xNextHandler->startElement(aName, xAttribs);
        }
    }
    catch (cssu::Exception& )
    {//getCaughtException MUST be the first line in the catch block
        cssu::Any exc =  cppu::getCaughtException();
        throw cssxs::SAXException(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
                              "xmlsecurity: Exception in XSecParser::startElement")),
            0, exc);
    }
    catch (...)
    {
        throw cssxs::SAXException(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xmlsecurity: unexpected exception in XSecParser::startElement")), 0,
            cssu::Any());
    }
}

void SAL_CALL XSecParser::endElement( const rtl::OUString& aName )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    try
    {
        if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_DIGESTVALUE)))
            {
                m_bInDigestValue = false;
            }
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_REFERENCE)) )
        {
            if ( m_bReferenceUnresolved )
            /*
            * it must be a octet stream
            */
            {
                m_pXSecController->addStreamReference( m_currentReferenceURI, sal_True);
                m_bReferenceUnresolved = false;
            }

            m_pXSecController->setDigestValue( m_ouDigestValue );
        }
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNEDINFO)) )
        {
            m_pXSecController->setReferenceCount();
        }
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_SIGNATUREVALUE)) )
        {
            m_pXSecController->setSignatureValue( m_ouSignatureValue );
                m_bInSignatureValue = false;
        }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509ISSUERNAME)))
            {
            m_pXSecController->setX509IssuerName( m_ouX509IssuerName );
            m_bInX509IssuerName = false;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509SERIALNUMBER)))
            {
            m_pXSecController->setX509SerialNumber( m_ouX509SerialNumber );
            m_bInX509SerialNumber = false;
            }
            else if (aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_X509CERTIFICATE)))
            {
            m_pXSecController->setX509Certificate( m_ouX509Certificate );
            m_bInX509Certificate = false;
            }
            else if (aName == rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(NSTAG_DC))
                        +rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":"))
                        +rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(TAG_DATE)))
        {
            m_pXSecController->setDate( m_ouDate );
                m_bInDate = false;
        }
        /*
        else if ( aName == rtl::OUString(RTL_ASCII_USTRINGPARAM(TAG_TIME)) )
        {
            m_pXSecController->setTime( m_ouTime );
                m_bInTime = false;
        }
        */

        if (m_xNextHandler.is())
        {
            m_xNextHandler->endElement(aName);
        }
    }
    catch (cssu::Exception& )
    {//getCaughtException MUST be the first line in the catch block
        cssu::Any exc =  cppu::getCaughtException();
        throw cssxs::SAXException(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
                              "xmlsecurity: Exception in XSecParser::endElement")),
            0, exc);
    }
    catch (...)
    {
        throw cssxs::SAXException(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xmlsecurity: unexpected exception in XSecParser::endElement")), 0,
            cssu::Any());
    }
}

void SAL_CALL XSecParser::characters( const rtl::OUString& aChars )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_bInX509IssuerName)
    {
        m_ouX509IssuerName += aChars;
    }
    else if (m_bInX509SerialNumber)
    {
        m_ouX509SerialNumber += aChars;
    }
    else if (m_bInX509Certificate)
    {
        m_ouX509Certificate += aChars;
    }
    else if (m_bInSignatureValue)
    {
        m_ouSignatureValue += aChars;
    }
    else if (m_bInDigestValue)
    {
        m_ouDigestValue += aChars;
    }
    else if (m_bInDate)
    {
        m_ouDate += aChars;
    }
    /*
    else if (m_bInTime)
    {
        m_ouTime += aChars;
    }
    */

    if (m_xNextHandler.is())
    {
        m_xNextHandler->characters(aChars);
        }
}

void SAL_CALL XSecParser::ignorableWhitespace( const rtl::OUString& aWhitespaces )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_xNextHandler.is())
    {
        m_xNextHandler->ignorableWhitespace( aWhitespaces );
        }
}

void SAL_CALL XSecParser::processingInstruction( const rtl::OUString& aTarget, const rtl::OUString& aData )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_xNextHandler.is())
    {
        m_xNextHandler->processingInstruction(aTarget, aData);
        }
}

void SAL_CALL XSecParser::setDocumentLocator( const cssu::Reference< cssxs::XLocator >& xLocator )
    throw (cssxs::SAXException, cssu::RuntimeException)
{
    if (m_xNextHandler.is())
    {
        m_xNextHandler->setDocumentLocator( xLocator );
        }
}

/*
 * XInitialization
 */
void SAL_CALL XSecParser::initialize(
    const cssu::Sequence< cssu::Any >& aArguments )
    throw(cssu::Exception, cssu::RuntimeException)
{
    aArguments[0] >>= m_xNextHandler;
}
<|endoftext|>


<commit_before>#pragma once

#include <Core/Utils/Log.hpp>

#include <functional>
#include <map>

namespace Ra {
namespace Core {
namespace Utils {

/// Simple observable implementation with void observer(Args...) notification.
/// Typical usage is to derive from Observer with the intended \p Args as in
/// \code{.cpp}
/// class MyClass : public Oberservable<int> [...]
/// MyClass c;
/// c.attach(functor)
/// \endcode
/// Also a class can have Observable members, than act as slots
/// \code{.cpp}
/// class MyClass {
/// public :
///   Oberservable<int> slot0;
///   Oberservable<> slot1;
///   void f(){ slot0.notify(10); }
/// };
/// MyClass c;
/// c.slot0.attach(functor)
/// c.slot1.attach(functor)
/// \endcode

template <typename... Args>
class Observable
{
  public:
    /// Observer functor type
    using Observer = std::function<void( Args... )>;

    /// Default constructor ... do nothing ;)
    Observable()                    = default;
    Observable( const Observable& ) = delete;
    Observable& operator=( const Observable& ) = delete;
    virtual ~Observable()                      = default;

    /// explicit copy of all attached observers the \p other Observable
    void copyObserversTo( Observable& other ) const {
        for ( const auto& o : m_observers )
        {
            other.attach( o.second );
        }
    }

    /// Attach an \p observer that will be call on subsecant call to notify()
    /// \return An unique int to identify the observer, could be used to pass to Obeservable::detach
    inline int attach( Observer observer ) {
        m_observers.insert( std::make_pair( ++m_currentId, observer ) );
        return m_currentId;
    }

    /// Utility function that extract the observer from a class member.
    /// Attach an \p observer that will be call on subsecant call to notify()
    /// \return An unique int to identify the observer, could be used to pass to Obeservable::detach
    template <typename T>
    int attachMember( T* object, void ( T::*observer )( Args... ) ) {
        return attach( std::bind( observer, object, std::placeholders::_1 ) );
    }

    /// Notify (i.e. call) each attached observer with argument \p p
    inline void notify( Args... p ) const {
        for ( const auto& o : m_observers )
            o.second( std::forward<Args>( p )... );
    }

    /// Detach all observers
    inline void detachAll() { m_observers.clear(); }

    /// Detach the \p observerId, observerId must have been saved from a
    /// previous call to attach
    inline void detach( int observerId ) { m_observers.erase( observerId ); }

  private:
    std::map<int, Observer> m_observers;
    int m_currentId {0};
};

class RA_CORE_API ObservableVoid : public Observable<>
{};

} // namespace Utils
} // namespace Core
} // namespace Ra
<commit_msg>[core] use {} init instead of make_pair<commit_after>#pragma once

#include <Core/Utils/Log.hpp>

#include <functional>
#include <map>

namespace Ra {
namespace Core {
namespace Utils {

/// Simple observable implementation with void observer(Args...) notification.
/// Typical usage is to derive from Observer with the intended \p Args as in
/// \code{.cpp}
/// class MyClass : public Oberservable<int> [...]
/// MyClass c;
/// c.attach(functor)
/// \endcode
/// Also a class can have Observable members, than act as slots
/// \code{.cpp}
/// class MyClass {
/// public :
///   Oberservable<int> slot0;
///   Oberservable<> slot1;
///   void f(){ slot0.notify(10); }
/// };
/// MyClass c;
/// c.slot0.attach(functor)
/// c.slot1.attach(functor)
/// \endcode

template <typename... Args>
class Observable
{
  public:
    /// Observer functor type
    using Observer = std::function<void( Args... )>;

    /// Default constructor ... do nothing ;)
    Observable()                    = default;
    Observable( const Observable& ) = delete;
    Observable& operator=( const Observable& ) = delete;
    virtual ~Observable()                      = default;

    /// explicit copy of all attached observers the \p other Observable
    void copyObserversTo( Observable& other ) const {
        for ( const auto& o : m_observers )
        {
            other.attach( o.second );
        }
    }

    /// Attach an \p observer that will be call on subsecant call to notify()
    /// \return An unique int to identify the observer, could be used to pass to Obeservable::detach
    inline int attach( Observer observer ) {
        m_observers.insert( {++m_currentId, observer} );
        return m_currentId;
    }

    /// Utility function that extract the observer from a class member.
    /// Attach an \p observer that will be call on subsecant call to notify()
    /// \return An unique int to identify the observer, could be used to pass to Obeservable::detach
    template <typename T>
    int attachMember( T* object, void ( T::*observer )( Args... ) ) {
        return attach( std::bind( observer, object, std::placeholders::_1 ) );
    }

    /// Notify (i.e. call) each attached observer with argument \p p
    inline void notify( Args... p ) const {
        for ( const auto& o : m_observers )
            o.second( std::forward<Args>( p )... );
    }

    /// Detach all observers
    inline void detachAll() { m_observers.clear(); }

    /// Detach the \p observerId, observerId must have been saved from a
    /// previous call to attach
    inline void detach( int observerId ) { m_observers.erase( observerId ); }

  private:
    std::map<int, Observer> m_observers;
    int m_currentId {0};
};

class RA_CORE_API ObservableVoid : public Observable<>
{};

} // namespace Utils
} // namespace Core
} // namespace Ra
<|endoftext|>


<commit_before>// RUN: cat %s | %cling | FileCheck %s

// This test makes sure the interpreter doesn't create many useless empty
// transactions.

// Author: Vassil Vassilev

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Transaction.h"
#include <stdio.h>

.rawInput 1

void generateNestedTransaction(int depth) {
  if (!depth)
    return;
  cling::Interpreter::PushTransactionRAII RAIIT(gCling);
  if (depth | 0x1) { // if odd
    char buff[100];
    sprintf(buff, "int i%d;", depth);
    gCling->process(buff);
  } // this will cause every even transaction to be reused.
  generateNestedTransaction(--depth);
}

.rawInput 0

generateNestedTransaction(5);
const cling::Transaction* T = gCling->getFirstTransaction();
while(T) {
  if (!T->size())
    printf("Empty transaction detected!\n");
  //T->printStructure();
  T = T->getNext();
}
printf("Just make FileCheck(CHECK-NOT) happy.\n")
//CHECK-NOT:Empty transaction detected!
.q
<commit_msg>Add more checks.<commit_after>// RUN: cat %s | %cling | FileCheck %s

// This test makes sure the interpreter doesn't create many useless empty
// transactions.

// Author: Vassil Vassilev

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Transaction.h"

#include "clang/AST/Decl.h"

#include <stdio.h>

.rawInput 1

void generateNestedTransaction(int depth) {
  if (!depth)
    return;
  cling::Interpreter::PushTransactionRAII RAIIT(gCling);
  if (depth | 0x1) { // if odd
    char buff[100];
    sprintf(buff, "int i%d;", depth);
    gCling->process(buff);
  } // this will cause every even transaction to be reused.
  generateNestedTransaction(--depth);
}

.rawInput 0

generateNestedTransaction(5);
const cling::Transaction* T = gCling->getFirstTransaction();
while(T) {
  if (!T->size())
    printf("Empty transaction detected!\n");
  if (T->getWrapperFD()->getKind() != Decl::Function)
    printf("Unexpected wrapper kind!\n");
  if (T->getState != Transaction::kCommitted)
    printf("Unexpected transaction state!\n");
  //T->printStructure();
  T = T->getNext();
}
printf("Just make FileCheck(CHECK-NOT) happy.\n")
//CHECK-NOT:Empty transaction detected!
//CHECK-NOT:Unexpected wrapper kind!
//CHECK-NOT:Unexpected transaction state!
.q
<|endoftext|>


<commit_before>/*
*  @file 		    ex6.cpp
*  @details  	  This file is the solution to exercise 6.
*  @author    	Alexander Rettkowski
*  @date      	28.06.2017
*/
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths_no_color_map.hpp>
#include <boost/property_map/property_map.hpp>

#include <boost/timer/timer.hpp>
#include <boost/chrono.hpp>

#include <iostream>
#include <string>
#include <complex>
#include <fstream>

using namespace boost;

namespace exercise5
{
	namespace qi = boost::spirit::qi;
	namespace ascii = boost::spirit::ascii;
	struct edge
	{
		int startNode;
		int endNode;
		int length;
	};
}

BOOST_FUSION_ADAPT_STRUCT(
	exercise5::edge,
	(int, startNode)
	(int, endNode)
	(int, length)
)

namespace exercise5
{
	template <typename Iterator>
	struct line_parser : qi::grammar<Iterator, edge()>
	{
		line_parser() : line_parser::base_type(start)
		{
			using qi::int_;
			start %= int_ >> ' ' >> int_ >> ' ' >> int_;
		}

		qi::rule<Iterator, edge()> start;
	};
}

/**
* The main function that reads in a file and processes it.
* @param argc Number of command line arguments.
* @param *argv a pointer to the array of command line arguments.
*/
int main(int argc, char *argv[])
{
	timer::cpu_timer boostTimer;
	typedef adjacency_list < listS, vecS, undirectedS, no_property, property < edge_weight_t, int > > graph_t;
	typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
	typedef std::pair<int, int> Edge;

	std::vector<Edge> edges;
	std::vector<int> weights;

	using boost::spirit::ascii::space;
	typedef std::string::const_iterator iterator_type;
	typedef exercise5::line_parser<iterator_type> line_parser;
	line_parser parser;
	std::string currentLine;
	std::ifstream file(argv[1]);

	// get number of nodes
	char delimiter = ' ';
	getline(file, currentLine, delimiter);
	int numberOfNodes = stoi(currentLine);
	getline(file, currentLine);
	int constSub = 1;
	while (getline(file, currentLine))
	{
		exercise5::edge parsedLine;
		std::string::const_iterator currentPosition = currentLine.begin();
		std::string::const_iterator lineEnd = currentLine.end();
		bool parsingSucceeded = phrase_parse(currentPosition, lineEnd, parser, space, parsedLine);

		if (parsingSucceeded && currentPosition == lineEnd)
		{
			edges.push_back(Edge(parsedLine.startNode - constSub, parsedLine.endNode - constSub));
			weights.push_back(parsedLine.length);
		}
	}

	file.close();

	graph_t g(edges.data(), edges.data() + edges.size(), weights.data(), numberOfNodes);

	property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
	std::vector<vertex_descriptor> p(num_vertices(g));
	std::vector<int> d(num_vertices(g));
	vertex_descriptor s = vertex(0 + constSub, g);

	dijkstra_shortest_paths_no_color_map(g, s, predecessor_map(make_iterator_property_map(p.begin(), get(vertex_index, g))).
		distance_map(make_iterator_property_map(d.begin(), get(vertex_index, g))));

	graph_traits < graph_t >::vertex_iterator vi, vend;
	size_t vertex = -1;
	double distance = -1;
	for (tie(vi, vend) = vertices(g); vi != vend; ++vi) {
		if (d[*vi] > distance)
		{
			distance = d[*vi];
			vertex = *vi;
		}
		if ((d[*vi] == distance) && (*vi > vertex))
		{
			vertex = *vi;
		}
	}

	std::cout << "RESULT VERTEX " << vertex << std::endl;
	std::cout << "RESULT DIST " << distance << std::endl;

	timer::cpu_times time = boostTimer.elapsed();
	std::cout << "CPU TIME: " << (time.user + time.system) / 1e9 << "s\n";
	std::cout << "WALL CLOCK TIME: " << time.wall / 1e9 << "s\n";

	return 0;
}
<commit_msg>Update ex6.cpp<commit_after>/*
*  @file 		    ex6.cpp
*  @details  	  This file is the solution to exercise 6.
*  @author    	Alexander Rettkowski
*  @date      	28.06.2017
*/
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths_no_color_map.hpp>
#include <boost/property_map/property_map.hpp>

#include <boost/timer/timer.hpp>
#include <boost/chrono.hpp>

#include <iostream>
#include <string>
#include <complex>
#include <fstream>

using namespace boost;

namespace exercise5
{
	namespace qi = boost::spirit::qi;
	namespace ascii = boost::spirit::ascii;
	struct edge
	{
		int startNode;
		int endNode;
		int length;
	};
}

BOOST_FUSION_ADAPT_STRUCT(
	exercise5::edge,
	(int, startNode)
	(int, endNode)
	(int, length)
)

namespace exercise5
{
	template <typename Iterator>
	struct line_parser : qi::grammar<Iterator, edge()>
	{
		line_parser() : line_parser::base_type(start)
		{
			using qi::int_;
			start %= int_ >> ' ' >> int_ >> ' ' >> int_;
		}

		qi::rule<Iterator, edge()> start;
	};
}

/**
* The main function that reads in a file and processes it.
* @param argc Number of command line arguments.
* @param *argv a pointer to the array of command line arguments.
*/
int main(int argc, char *argv[])
{
	timer::cpu_timer boostTimer;
	typedef adjacency_list < listS, vecS, undirectedS, no_property, property < edge_weight_t, int > > graph_t;
	typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
	typedef std::pair<int, int> Edge;

	std::vector<Edge> edges;
	std::vector<int> weights;

	using boost::spirit::ascii::space;
	typedef std::string::const_iterator iterator_type;
	typedef exercise5::line_parser<iterator_type> line_parser;
	line_parser parser;
	std::string currentLine;
	std::ifstream file(argv[1]);

	// get number of nodes
	char delimiter = ' ';
	getline(file, currentLine, delimiter);
	int numberOfNodes = stoi(currentLine);
	getline(file, currentLine);
	int constSub = 1;
	while (getline(file, currentLine))
	{
		exercise5::edge parsedLine;
		std::string::const_iterator currentPosition = currentLine.begin();
		std::string::const_iterator lineEnd = currentLine.end();
		bool parsingSucceeded = phrase_parse(currentPosition, lineEnd, parser, space, parsedLine);

		if (parsingSucceeded && currentPosition == lineEnd)
		{
			edges.push_back(Edge(parsedLine.startNode - constSub, parsedLine.endNode - constSub));
			weights.push_back(parsedLine.length);
		}
	}

	file.close();

	graph_t g(edges.data(), edges.data() + edges.size(), weights.data(), numberOfNodes);

	property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
	std::vector<vertex_descriptor> p(num_vertices(g));
	std::vector<int> d(num_vertices(g));
	vertex_descriptor s = vertex(0, g);

	dijkstra_shortest_paths_no_color_map(g, s, predecessor_map(make_iterator_property_map(p.begin(), get(vertex_index, g))).
		distance_map(make_iterator_property_map(d.begin(), get(vertex_index, g))));

	graph_traits < graph_t >::vertex_iterator vi, vend;
	size_t vertex = -1;
	double distance = -1;
	for (tie(vi, vend) = vertices(g); vi != vend; ++vi) {
		if (d[*vi] > distance)
		{
			distance = d[*vi];
			vertex = *vi;
		}
		if ((d[*vi] == distance) && (*vi > vertex))
		{
			vertex = *vi;
		}
	}

	std::cout << "RESULT VERTEX " << vertex << std::endl;
	std::cout << "RESULT DIST " << distance << std::endl;

	timer::cpu_times time = boostTimer.elapsed();
	std::cout << "CPU TIME: " << (time.user + time.system) / 1e9 << "s\n";
	std::cout << "WALL CLOCK TIME: " << time.wall / 1e9 << "s\n";

	return 0;
}
<|endoftext|>


<commit_before>/*
 * ============================================================================
 *
 *       Filename:  qcpipeline.cc
 *    Description:  A demonstration of how to run a processor pipline with
 *                  libqc++
 *        License:  LGPL-3+
 *         Author:  Kevin Murray, spam@kdmurray.id.au
 *
 * ============================================================================
 */

#include <iostream>
#include <fstream>
#include <string>

#include "qcpp.hh"

#include "qc-measure.hh"
#include "qc-length.hh"

int
main (int argc, char *argv[])
{
    std::ofstream yml_output;
    qcpp::ProcessedReadStream stream;
    uint64_t n_pairs = 0;

    if (argc != 3) {
        std::cerr << "USAGE: " << argv[0] << " <read_file> <yml_file>"
                  << std::endl;
        return EXIT_FAILURE;
    }

    stream.open(argv[1]);
    yml_output.open(argv[2]);
    stream.append_processor<qcpp::PerBaseQuality>("before qc");
    stream.append_processor<qcpp::ReadLenFilter>("trim at 50", 50);
    stream.append_processor<qcpp::ReadLenCounter>("after qc");

    // to enable paralleism uncomment these
    //#pragma omp parallel
    {
        qcpp::ReadPair rp;
        while (stream.parse_read_pair(rp)) {
            // __sync_fetch_and_add(&n_pairs, 1);
            if (n_pairs++ % 100000 == 0) {
                std::cerr << "Processed " << n_pairs << "\r";
            }
            //#pragma omp critical
            {
                // std::cout << rp.str();
            }
        }
    }
    std::cerr << "Processed " << n_pairs << std::endl;
    yml_output << stream.report();
    return EXIT_SUCCESS;
}
<commit_msg>New gbsqc program, pre trim<commit_after>/*
 * ============================================================================
 *
 *       Filename:  qcpipeline.cc
 *    Description:  A demonstration of how to run a processor pipline with
 *                  libqc++
 *        License:  LGPL-3+
 *         Author:  Kevin Murray, spam@kdmurray.id.au
 *
 * ============================================================================
 */

#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <iomanip>

#include "qcpp.hh"

#include "qc-measure.hh"
#include "qc-length.hh"
#include "qc-qualtrim.hh"
#include "qc-gbs.hh"

using std::chrono::system_clock;

inline void
progress(size_t n, system_clock::time_point start)
{
    std::chrono::duration<double> tdiff = system_clock::now() - start;
    double secs = tdiff.count();
    double k_reads = n / 1000.0;
    double rate = k_reads / secs;
    std::cerr << "\x1b[2K" << "Kept " << k_reads << "K read pairs in "
              << (int)secs << "s (" << std::setprecision(3) << rate
              << std::setprecision(9) << "K RP/sec)\r";
}

int
main (int argc, char *argv[])
{

    if (argc != 3) {
        std::cerr << "USAGE: " << argv[0] << " <read_file> <yml_file>"
                  << std::endl;
        return EXIT_FAILURE;
    }

    qcpp::ProcessedReadStream   stream(argv[1]);
    std::ofstream               yml_output(argv[2]);
    uint64_t                    n_pairs = 0;

    //stream.append_processor<qcpp::PerBaseQuality>("before qc");
    stream.append_processor<qcpp::GBSTrimPE>("trim Pst1 read-through", "CTGCAG", 1);
    stream.append_processor<qcpp::WindowedQualTrim>("QC", 28, 33, 50);
    //stream.append_processor<qcpp::PerBaseQuality>("after qc");

    system_clock::time_point start = system_clock::now();
    // to enable paralleism uncomment these
    //#pragma omp parallel
    {
        //std::ostringstream oss;
        qcpp::ReadPair rp;
        while (stream.parse_read_pair(rp)) {
            if (n_pairs % 100000 == 0) {
                //#pragma omp critical
                {
                    progress(n_pairs, start);
                    //std::cout << oss.str();
                }
                //oss.str("");
                //oss.clear();
            }
            //oss << rp.str();
            //__sync_fetch_and_add(&n_pairs, 1);
            n_pairs++;
        }
    }
    progress(n_pairs, start);
    std::cerr << std::endl;
    yml_output << stream.report();
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before><commit_msg>fix scanline check for multi-threading (when y-res < thnum)<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/des.h"

#include "base/logging.h"

#if defined(USE_NSS)
#include <nss.h>
#include <pk11pub.h>
#include "base/nss_util.h"
#elif defined(OS_MACOSX)
#include <CommonCrypto/CommonCryptor.h>
#elif defined(OS_WIN)
#include <windows.h>
#include <wincrypt.h>
#include "base/crypto/scoped_capi_types.h"
#endif

// The Mac and Windows (CryptoAPI) versions of DESEncrypt are our own code.
// DESSetKeyParity, DESMakeKey, and the Linux (NSS) version of DESEncrypt are
// based on mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp,
// CVS rev. 1.14.

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla.
 *
 * The Initial Developer of the Original Code is IBM Corporation.
 * Portions created by IBM Corporation are Copyright (C) 2003
 * IBM Corporation. All Rights Reserved.
 *
 * Contributor(s):
 *   Darin Fisher <darin@meer.net>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// Set odd parity bit (in least significant bit position).
static uint8 DESSetKeyParity(uint8 x) {
  if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^
        (x >> 4) ^ (x >> 3) ^ (x >> 2) ^
        (x >> 1)) & 0x01) == 0) {
    x |= 0x01;
  } else {
    x &= 0xfe;
  }
  return x;
}

namespace net {

void DESMakeKey(const uint8* raw, uint8* key) {
  key[0] = DESSetKeyParity(raw[0]);
  key[1] = DESSetKeyParity((raw[0] << 7) | (raw[1] >> 1));
  key[2] = DESSetKeyParity((raw[1] << 6) | (raw[2] >> 2));
  key[3] = DESSetKeyParity((raw[2] << 5) | (raw[3] >> 3));
  key[4] = DESSetKeyParity((raw[3] << 4) | (raw[4] >> 4));
  key[5] = DESSetKeyParity((raw[4] << 3) | (raw[5] >> 5));
  key[6] = DESSetKeyParity((raw[5] << 2) | (raw[6] >> 6));
  key[7] = DESSetKeyParity((raw[6] << 1));
}

#if defined(USE_OPENSSL)

void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
  // TODO(joth): When implementing consider splitting up this file by platform.
  NOTIMPLEMENTED();
}

#elif defined(USE_NSS)

void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
  CK_MECHANISM_TYPE cipher_mech = CKM_DES_ECB;
  PK11SlotInfo* slot = NULL;
  PK11SymKey* symkey = NULL;
  PK11Context* ctxt = NULL;
  SECItem key_item;
  SECItem* param = NULL;
  SECStatus rv;
  unsigned int n;

  base::EnsureNSSInit();

  slot = PK11_GetBestSlot(cipher_mech, NULL);
  if (!slot)
    goto done;

  key_item.data = const_cast<uint8*>(key);
  key_item.len = 8;
  symkey = PK11_ImportSymKey(slot, cipher_mech,
                             PK11_OriginUnwrap, CKA_ENCRYPT,
                             &key_item, NULL);
  if (!symkey)
    goto done;

  // No initialization vector required.
  param = PK11_ParamFromIV(cipher_mech, NULL);
  if (!param)
    goto done;

  ctxt = PK11_CreateContextBySymKey(cipher_mech, CKA_ENCRYPT,
                                    symkey, param);
  if (!ctxt)
    goto done;

  rv = PK11_CipherOp(ctxt, hash, reinterpret_cast<int*>(&n), 8,
                     const_cast<uint8*>(src), 8);
  if (rv != SECSuccess)
    goto done;

  // TODO(wtc): Should this be PK11_Finalize?
  rv = PK11_DigestFinal(ctxt, hash+8, &n, 0);
  if (rv != SECSuccess)
    goto done;

 done:
  if (ctxt)
    PK11_DestroyContext(ctxt, PR_TRUE);
  if (symkey)
    PK11_FreeSymKey(symkey);
  if (param)
    SECITEM_FreeItem(param, PR_TRUE);
  if (slot)
    PK11_FreeSlot(slot);
}

#elif defined(OS_MACOSX)

void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
  CCCryptorStatus status;
  size_t data_out_moved = 0;
  status = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode,
                   key, 8, NULL, src, 8, hash, 8, &data_out_moved);
  DCHECK(status == kCCSuccess);
  DCHECK(data_out_moved == 8);
}

#elif defined(OS_WIN)

void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
  base::ScopedHCRYPTPROV provider;
  if (!CryptAcquireContext(provider.receive(), NULL, NULL, PROV_RSA_FULL,
                           CRYPT_VERIFYCONTEXT))
    return;

  {
    // Import the DES key.
    struct KeyBlob {
      BLOBHEADER header;
      DWORD key_size;
      BYTE key_data[8];
    };
    KeyBlob key_blob;
    key_blob.header.bType = PLAINTEXTKEYBLOB;
    key_blob.header.bVersion = CUR_BLOB_VERSION;
    key_blob.header.reserved = 0;
    key_blob.header.aiKeyAlg = CALG_DES;
    key_blob.key_size = 8;  // 64 bits
    memcpy(key_blob.key_data, key, 8);

    base::ScopedHCRYPTKEY key;
    BOOL import_ok = CryptImportKey(provider,
                                    reinterpret_cast<BYTE*>(&key_blob),
                                    sizeof key_blob, 0, 0, key.receive());
    // Destroy the copy of the key.
    SecureZeroMemory(key_blob.key_data, sizeof key_blob.key_data);
    if (!import_ok)
      return;

    // No initialization vector required.
    DWORD cipher_mode = CRYPT_MODE_ECB;
    if (!CryptSetKeyParam(key, KP_MODE, reinterpret_cast<BYTE*>(&cipher_mode),
                          0))
      return;

    // CryptoAPI requires us to copy the plaintext to the output buffer first.
    CopyMemory(hash, src, 8);
    // Pass a 'Final' of FALSE, otherwise CryptEncrypt appends one additional
    // block of padding to the data.
    DWORD hash_len = 8;
    CryptEncrypt(key, 0, FALSE, 0, hash, &hash_len, 8);
  }
}

#elif defined(USE_OPENSSL) && defined(ANDROID)

// To be implemented with openssl
void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
    int* a = NULL;
    int c = *a;
}

#endif

}  // namespace net
<commit_msg>Fix for bug 2386130 VZW:PP659: login issues on some sites:http://traffic.cumulus.com - LIBtt61764 (NTLM support) do not merge<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/des.h"

#include "base/logging.h"

#if defined(USE_NSS)
#include <nss.h>
#include <pk11pub.h>
#include "base/nss_util.h"
#elif defined(USE_OPENSSL)
#include <openssl/des.h>
#elif defined(OS_MACOSX)
#include <CommonCrypto/CommonCryptor.h>
#elif defined(OS_WIN)
#include <windows.h>
#include <wincrypt.h>
#include "base/crypto/scoped_capi_types.h"
#endif

// The Mac and Windows (CryptoAPI) versions of DESEncrypt are our own code.
// DESSetKeyParity, DESMakeKey, and the Linux (NSS) version of DESEncrypt are
// based on mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp,
// CVS rev. 1.14.

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla.
 *
 * The Initial Developer of the Original Code is IBM Corporation.
 * Portions created by IBM Corporation are Copyright (C) 2003
 * IBM Corporation. All Rights Reserved.
 *
 * Contributor(s):
 *   Darin Fisher <darin@meer.net>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// Set odd parity bit (in least significant bit position).
static uint8 DESSetKeyParity(uint8 x) {
  if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^
        (x >> 4) ^ (x >> 3) ^ (x >> 2) ^
        (x >> 1)) & 0x01) == 0) {
    x |= 0x01;
  } else {
    x &= 0xfe;
  }
  return x;
}

namespace net {

void DESMakeKey(const uint8* raw, uint8* key) {
  key[0] = DESSetKeyParity(raw[0]);
  key[1] = DESSetKeyParity((raw[0] << 7) | (raw[1] >> 1));
  key[2] = DESSetKeyParity((raw[1] << 6) | (raw[2] >> 2));
  key[3] = DESSetKeyParity((raw[2] << 5) | (raw[3] >> 3));
  key[4] = DESSetKeyParity((raw[3] << 4) | (raw[4] >> 4));
  key[5] = DESSetKeyParity((raw[4] << 3) | (raw[5] >> 5));
  key[6] = DESSetKeyParity((raw[5] << 2) | (raw[6] >> 6));
  key[7] = DESSetKeyParity((raw[6] << 1));
}

#if defined(USE_OPENSSL)

void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
  DES_cblock des_key;
  DES_key_schedule schedule;

  memcpy(des_key, key, 8);
  DES_set_odd_parity(&des_key);
  DES_set_key_checked(&des_key, &schedule);

  DES_ecb_encrypt((C_Block *)src, (C_Block *)hash, &schedule, DES_ENCRYPT);
}

#elif defined(USE_NSS)

void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
  CK_MECHANISM_TYPE cipher_mech = CKM_DES_ECB;
  PK11SlotInfo* slot = NULL;
  PK11SymKey* symkey = NULL;
  PK11Context* ctxt = NULL;
  SECItem key_item;
  SECItem* param = NULL;
  SECStatus rv;
  unsigned int n;

  base::EnsureNSSInit();

  slot = PK11_GetBestSlot(cipher_mech, NULL);
  if (!slot)
    goto done;

  key_item.data = const_cast<uint8*>(key);
  key_item.len = 8;
  symkey = PK11_ImportSymKey(slot, cipher_mech,
                             PK11_OriginUnwrap, CKA_ENCRYPT,
                             &key_item, NULL);
  if (!symkey)
    goto done;

  // No initialization vector required.
  param = PK11_ParamFromIV(cipher_mech, NULL);
  if (!param)
    goto done;

  ctxt = PK11_CreateContextBySymKey(cipher_mech, CKA_ENCRYPT,
                                    symkey, param);
  if (!ctxt)
    goto done;

  rv = PK11_CipherOp(ctxt, hash, reinterpret_cast<int*>(&n), 8,
                     const_cast<uint8*>(src), 8);
  if (rv != SECSuccess)
    goto done;

  // TODO(wtc): Should this be PK11_Finalize?
  rv = PK11_DigestFinal(ctxt, hash+8, &n, 0);
  if (rv != SECSuccess)
    goto done;

 done:
  if (ctxt)
    PK11_DestroyContext(ctxt, PR_TRUE);
  if (symkey)
    PK11_FreeSymKey(symkey);
  if (param)
    SECITEM_FreeItem(param, PR_TRUE);
  if (slot)
    PK11_FreeSlot(slot);
}

#elif defined(OS_MACOSX)

void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
  CCCryptorStatus status;
  size_t data_out_moved = 0;
  status = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode,
                   key, 8, NULL, src, 8, hash, 8, &data_out_moved);
  DCHECK(status == kCCSuccess);
  DCHECK(data_out_moved == 8);
}

#elif defined(OS_WIN)

void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
  base::ScopedHCRYPTPROV provider;
  if (!CryptAcquireContext(provider.receive(), NULL, NULL, PROV_RSA_FULL,
                           CRYPT_VERIFYCONTEXT))
    return;

  {
    // Import the DES key.
    struct KeyBlob {
      BLOBHEADER header;
      DWORD key_size;
      BYTE key_data[8];
    };
    KeyBlob key_blob;
    key_blob.header.bType = PLAINTEXTKEYBLOB;
    key_blob.header.bVersion = CUR_BLOB_VERSION;
    key_blob.header.reserved = 0;
    key_blob.header.aiKeyAlg = CALG_DES;
    key_blob.key_size = 8;  // 64 bits
    memcpy(key_blob.key_data, key, 8);

    base::ScopedHCRYPTKEY key;
    BOOL import_ok = CryptImportKey(provider,
                                    reinterpret_cast<BYTE*>(&key_blob),
                                    sizeof key_blob, 0, 0, key.receive());
    // Destroy the copy of the key.
    SecureZeroMemory(key_blob.key_data, sizeof key_blob.key_data);
    if (!import_ok)
      return;

    // No initialization vector required.
    DWORD cipher_mode = CRYPT_MODE_ECB;
    if (!CryptSetKeyParam(key, KP_MODE, reinterpret_cast<BYTE*>(&cipher_mode),
                          0))
      return;

    // CryptoAPI requires us to copy the plaintext to the output buffer first.
    CopyMemory(hash, src, 8);
    // Pass a 'Final' of FALSE, otherwise CryptEncrypt appends one additional
    // block of padding to the data.
    DWORD hash_len = 8;
    CryptEncrypt(key, 0, FALSE, 0, hash, &hash_len, 8);
  }
}

#endif

}  // namespace net
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "include/script.h"
#include "include/debug.h"
#include <lua.hpp>

namespace yappy {
namespace lua {
namespace export {

namespace {

// Get reinterpret_cast<T *>(self.fieldName)
// self is the first argument (stack[1])
template <class T>
inline T *getPtrFromSelf(lua_State *L, const char *fieldName)
{
	luaL_checktype(L, 1, LUA_TTABLE);
	lua_getfield(L, 1, fieldName);
	luaL_checktype(L, -1, LUA_TLIGHTUSERDATA);
	void *p = lua_touserdata(L, -1);
	T *result = reinterpret_cast<T *>(p);
	lua_pop(L, 1);
	return result;
}

inline int getIntWithDefault(lua_State *L, int idx, int def)
{
	if (!lua_isnone(L, idx)) {
		return static_cast<int>(luaL_checkinteger(L, idx));
	}
	else {
		return def;
	}
}

inline float getFloatWithDefault(lua_State *L, int idx, float def)
{
	if (!lua_isnone(L, idx)) {
		return static_cast<float>(luaL_checknumber(L, idx));
	}
	else {
		return def;
	}
}

inline bool getBooleanWithDefault(lua_State *L, int idx, bool def)
{
	if (!lua_isnone(L, idx)) {
		return lua_toboolean(L, idx) != 0;
	}
	else {
		return def;
	}
}

}	// namespace

///////////////////////////////////////////////////////////////////////////////
// "trace" table
///////////////////////////////////////////////////////////////////////////////

/** @brief デバッグ出力する。
 * @details
 * @code
 * function trace.write(...)
 * end
 * @endcode
 *
 * @param[in]	...	任意の型および数の出力する値
 * @return			なし
 */
int trace::write(lua_State *L)
{
	int argc = lua_gettop(L);
	for (int i = 1; i <= argc; i++) {
		const char *str = ::lua_tostring(L, i);
		if (str != nullptr) {
			debug::writeLine(str);
		}
		else {
			debug::writef("<%s>", luaL_typename(L, i));
		}
	}
	return 0;
}

///////////////////////////////////////////////////////////////////////////////
// "resource" table
///////////////////////////////////////////////////////////////////////////////

/** @brief テクスチャリソースを登録する。
 * @details
 * @code
 * function resource:addTexture(int setId, str resId, str path)
 * end
 * @endcode
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	path	ファイルパス
 * @return				なし
 */
int resource::addTexture(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, resource_RawFieldName);
	int setId = static_cast<int>(luaL_checkinteger(L, 2));
	const char *resId = luaL_checkstring(L, 3);
	const char *path = luaL_checkstring(L, 4);

	app->addTextureResource(setId, resId, util::utf82wc(path).get());

	return 0;
}

/** @brief フォントリソースを登録する。
 * @details
 * @code
 * function resource:addFont(int setId, str resId, str path)
 * end
 * @endcode
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	path	ファイルパス
 * @return				なし
 */
int resource::addFont(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, resource_RawFieldName);
	int setId = static_cast<int>(luaL_checkinteger(L, 2));
	const char *resId = luaL_checkstring(L, 3);
	const char *fontName = luaL_checkstring(L, 4);
	const char *startCharStr = luaL_checkstring(L, 5);
	const char *endCharStr = luaL_checkstring(L, 6);
	int w = static_cast<int>(luaL_checkinteger(L, 7));
	int h = static_cast<int>(luaL_checkinteger(L, 8));

	wchar_t startChar = util::utf82wc(startCharStr)[0];
	wchar_t endChar = util::utf82wc(endCharStr)[0];

	app->addFontResource(setId, resId, util::utf82wc(fontName).get(),
		startChar, endChar, w, h);

	return 0;
}

/** @brief 効果音リソースを登録する。
 * @details
 * @code
 * function resource:addSe(int setId, str resId, str path)
 * end
 * @endcode
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	path	ファイルパス
 * @return				なし
 */
int resource::addSe(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, resource_RawFieldName);
	int setId = static_cast<int>(luaL_checkinteger(L, 2));
	const char *resId = luaL_checkstring(L, 3);
	const char *path = luaL_checkstring(L, 4);

	app->addSeResource(setId, resId, util::utf82wc(path).get());

	return 0;
}

///////////////////////////////////////////////////////////////////////////////
// "graph" table
///////////////////////////////////////////////////////////////////////////////

/** @brief テクスチャのサイズを得る。
 * @details
 * @code
 * function graph:getTextureSize(int setId, str resId)
 * 	return w, h;
 * end
 * @endcode
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @retval		1		横の長さ
 * @retval		2		縦の長さ
 */
int graph::getTextureSize(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, graph_RawFieldName);
	int setId = static_cast<int>(luaL_checkinteger(L, 2));
	const char *resId = luaL_checkstring(L, 3);

	const auto &pTex = app->getTexture(setId, resId);

	lua_pushinteger(L, pTex->w);
	lua_pushinteger(L, pTex->h);

	return 2;
}

/** @brief テクスチャを描画する。
 * @details
 * @code
 * function graph:drawTexture(int setId, str resId,
 * 	int dx, int dy, bool lrInv = false, bool udInv = false,
 * 	int sx = 0, int sy = 0, int sw = -1, int sh = -1,
 * 	int cx = 0, int cy = 0, float angle = 0.0f,
 * 	float scaleX = 1.0f, float scaleY = 1.0f, float alpha = 1.0f)
 * end
 * @endcode
 * スクリーン座標 (dx, dy) に (cx, cy) が一致するように描画されます。
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	dx		描画先中心座標X
 * @param[in]	dy		描画先中心座標Y
 * @param[in]	lrInv	左右反転フラグ
 * @param[in]	udInv	上下反転フラグ
 * @param[in]	sx		テクスチャから切り出す際の左上座標X
 * @param[in]	sy		テクスチャから切り出す際の左上座標Y
 * @param[in]	sw		切り出しサイズX(-1でテクスチャサイズ)
 * @param[in]	sh		切り出しサイズY(-1でテクスチャサイズ)
 * @param[in]	cx		(sx, sy)基準の描画元中心座標X
 * @param[in]	cy		(sx, sy)基準の描画元中心座標Y
 * @param[in]	angle	回転角(rad)
 * @param[in]	scaleX	拡大率X
 * @param[in]	scaleY	拡大率Y
 * @param[in]	alpha	透明度(0.0 - 1.0)
 * @return				なし
 *
 * @sa graphics::DGraphics::drawTexture()
 * @bug sw, sh のデフォルトが0になっている。
 */
int graph::drawTexture(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, graph_RawFieldName);
	int setId = static_cast<int>(luaL_checkinteger(L, 2));
	const char *resId = luaL_checkstring(L, 3);
	int dx = static_cast<int>(luaL_checkinteger(L, 4));
	int dy = static_cast<int>(luaL_checkinteger(L, 5));

	bool lrInv = getBooleanWithDefault(L, 6, false);
	bool udInv = getBooleanWithDefault(L, 7, false);
	int sx = getIntWithDefault(L, 8, 0);
	int sy = getIntWithDefault(L, 9, 0);
	int sw = getIntWithDefault(L, 10, 0);
	int sh = getIntWithDefault(L, 11, 0);
	int cx = getIntWithDefault(L, 12, 0);
	int cy = getIntWithDefault(L, 13, 0);
	float angle = getFloatWithDefault(L, 14, 0.0f);
	float scaleX = getFloatWithDefault(L, 15, 1.0f);
	float scaleY = getFloatWithDefault(L, 16, 1.0f);
	float alpha = getFloatWithDefault(L, 17, 1.0f);

	const auto &pTex = app->getTexture(setId, resId);
	app->graph().drawTexture(pTex, dx, dy, lrInv, udInv, sx, sy, sw, sh, cx, cy,
		angle, scaleX, scaleY, alpha);

	return 0;
}

/** @brief 文字列を描画する。
 * @details
 * @code
 * function graph:drawString(int setId, str resId, str str, int dx, int dy,
 * 	int color = 0x000000, int ajustX = 0,
 * 	float scaleX = 1.0f, float scaleY = 1.0f, float alpha = 1.0f)
 * end
 * @endcode
 * スクリーン座標 (dx, dy) に (cx, cy) が一致するように描画されます。
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	str		描画する文字列
 * @param[in]	dx		描画先座標X
 * @param[in]	dy		描画先座標Y
 * @param[in]	color	文字色 (0xRRGGBB)
 * @param[in]	ajustX	文字間隔調整用X移動量
 * @param[in]	scaleX	拡大率X
 * @param[in]	scaleY	拡大率Y
 * @param[in]	alpha	透明度(0.0 - 1.0)
 * @return				なし
 *
 * @sa graphics::DGraphics::drawString()
 */
int graph::drawString(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, graph_RawFieldName);
	int setId = static_cast<int>(luaL_checkinteger(L, 2));
	const char *resId = luaL_checkstring(L, 3);
	const char *str = luaL_checkstring(L, 4);
	int dx = static_cast<int>(luaL_checkinteger(L, 5));
	int dy = static_cast<int>(luaL_checkinteger(L, 6));

	int color = getIntWithDefault(L, 7, 0x000000);
	int ajustX = getIntWithDefault(L, 8, 0);
	float scaleX = getFloatWithDefault(L, 9, 1.0f);
	float scaleY = getFloatWithDefault(L, 10, 1.0f);
	float alpha = getFloatWithDefault(L, 11, 1.0f);

	const auto &pFont = app->getFont(setId, resId);
	app->graph().drawString(pFont, util::utf82wc(str).get(), dx, dy,
		color, ajustX, scaleX, scaleY, alpha);

	return 0;
}

///////////////////////////////////////////////////////////////////////////////
// "sound" table
///////////////////////////////////////////////////////////////////////////////

/** @brief BGM 再生を開始する。
 * @details
 * @code
 * function sound:playBgm(str path)
 * end
 * @endcode
 *
 * @param[in]	path	BGM oggファイルのパス
 * @return				なし
 *
 * @todo 多分リソースベースのインタフェースに変えます。
 */
int sound::playBgm(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, sound_RawFieldName);
	const char *path = luaL_checkstring(L, 2);

	app->sound().playBgm(util::utf82wc(path).get());

	return 0;
}

/** @brief BGM 再生を停止する。
 * @details
 * @code
 * function sound:stopBgm()
 * end
 * @endcode
 *
 * @return				なし
 */
int sound::stopBgm(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, sound_RawFieldName);

	app->sound().stopBgm();

	return 0;
}

}
}
}
<commit_msg>Improve lua args check<commit_after>#include "stdafx.h"
#include "include/script.h"
#include "include/debug.h"
#include <lua.hpp>

namespace yappy {
namespace lua {
namespace export {

namespace {

// Get reinterpret_cast<T *>(self.fieldName)
// self is the first argument (stack[1])
template <class T>
inline T *getPtrFromSelf(lua_State *L, const char *fieldName)
{
	luaL_checktype(L, 1, LUA_TTABLE);
	lua_getfield(L, 1, fieldName);
	luaL_checktype(L, -1, LUA_TLIGHTUSERDATA);
	void *p = lua_touserdata(L, -1);
	T *result = reinterpret_cast<T *>(p);
	lua_pop(L, 1);
	return result;
}

template <class T>
using lim = std::numeric_limits<T>;

static_assert(lim<lua_Integer>::min() <= lim<int>::min(),	"Lua type check");
static_assert(lim<lua_Integer>::max() >= lim<int>::max(),	"Lua type check");
static_assert(lim<lua_Number>::max() >= lim<float>::max(),	"Lua type check");

inline int luaintToInt(lua_State *L, int arg,
	lua_Integer val, int min, int max)
{
	luaL_argcheck(L, val >= min, arg, "number too small");
	luaL_argcheck(L, val <= max, arg, "number too large");
	return static_cast<int>(val);
}

inline int getInt(lua_State *L, int arg,
	int min = std::numeric_limits<int>::min(),
	int max = std::numeric_limits<int>::max())
{
	lua_Integer val = luaL_checkinteger(L, arg);
	return luaintToInt(L, arg, val, min, max);
}

inline int getOptInt(lua_State *L, int arg, int def,
	int min = std::numeric_limits<int>::min(),
	int max = std::numeric_limits<int>::max())
{
	lua_Integer val = luaL_optinteger(L, arg, def);
	return luaintToInt(L, arg, val, min, max);
}

inline float luanumToFloat(lua_State *L, int arg,
	lua_Number val, float min, float max)
{
	luaL_argcheck(L, val >= min, arg, "number too small or NaN");
	luaL_argcheck(L, val <= max, arg, "number too large or NaN");
	return static_cast<float>(val);
}

inline float getFloat(lua_State *L, int arg,
	float min = std::numeric_limits<float>::lowest(),
	float max = std::numeric_limits<float>::max())
{
	lua_Number val = luaL_checknumber(L, arg);
	return luanumToFloat(L, arg, val, min, max);
}

inline float getOptFloat(lua_State *L, int arg, float def,
	float min = std::numeric_limits<float>::lowest(),
	float max = std::numeric_limits<float>::max())
{
	lua_Number val = luaL_optnumber(L, arg, def);
	return luanumToFloat(L, arg, val, min, max);
}

}	// namespace

///////////////////////////////////////////////////////////////////////////////
// "trace" table
///////////////////////////////////////////////////////////////////////////////

/** @brief デバッグ出力する。
 * @details
 * @code
 * function trace.write(...)
 * end
 * @endcode
 *
 * @param[in]	...	任意の型および数の出力する値
 * @return			なし
 */
int trace::write(lua_State *L)
{
	int argc = lua_gettop(L);
	for (int i = 1; i <= argc; i++) {
		const char *str = ::lua_tostring(L, i);
		if (str != nullptr) {
			debug::writeLine(str);
		}
		else {
			debug::writef("<%s>", luaL_typename(L, i));
		}
	}
	return 0;
}

///////////////////////////////////////////////////////////////////////////////
// "resource" table
///////////////////////////////////////////////////////////////////////////////

/** @brief テクスチャリソースを登録する。
 * @details
 * @code
 * function resource:addTexture(int setId, str resId, str path)
 * end
 * @endcode
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	path	ファイルパス
 * @return				なし
 */
int resource::addTexture(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, resource_RawFieldName);
	int setId = getInt(L, 2, 0);
	const char *resId = luaL_checkstring(L, 3);
	const char *path = luaL_checkstring(L, 4);

	app->addTextureResource(setId, resId, util::utf82wc(path).get());

	return 0;
}

/** @brief フォントリソースを登録する。
 * @details
 * @code
 * function resource:addFont(int setId, str resId, str path)
 * end
 * @endcode
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	path	ファイルパス
 * @return				なし
 */
int resource::addFont(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, resource_RawFieldName);
	int setId = getInt(L, 2, 0);
	const char *resId = luaL_checkstring(L, 3);
	const char *fontName = luaL_checkstring(L, 4);
	const char *startCharStr = luaL_checkstring(L, 5);
	luaL_argcheck(L, *startCharStr != '\0', 5, "empty string is NG");
	const char *endCharStr = luaL_checkstring(L, 6);
	luaL_argcheck(L, *endCharStr != '\0', 6, "empty string is NG");
	int w = getInt(L, 7, 0);
	int h = getInt(L, 8, 0);

	wchar_t startChar = util::utf82wc(startCharStr)[0];
	wchar_t endChar = util::utf82wc(endCharStr)[0];

	app->addFontResource(setId, resId, util::utf82wc(fontName).get(),
		startChar, endChar, w, h);

	return 0;
}

/** @brief 効果音リソースを登録する。
 * @details
 * @code
 * function resource:addSe(int setId, str resId, str path)
 * end
 * @endcode
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	path	ファイルパス
 * @return				なし
 */
int resource::addSe(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, resource_RawFieldName);
	int setId = getInt(L, 2, 0);
	const char *resId = luaL_checkstring(L, 3);
	const char *path = luaL_checkstring(L, 4);

	app->addSeResource(setId, resId, util::utf82wc(path).get());

	return 0;
}

///////////////////////////////////////////////////////////////////////////////
// "graph" table
///////////////////////////////////////////////////////////////////////////////

/** @brief テクスチャのサイズを得る。
 * @details
 * @code
 * function graph:getTextureSize(int setId, str resId)
 * 	return w, h;
 * end
 * @endcode
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @retval		1		横の長さ
 * @retval		2		縦の長さ
 */
int graph::getTextureSize(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, graph_RawFieldName);
	int setId = getInt(L, 2, 0);
	const char *resId = luaL_checkstring(L, 3);

	const auto &pTex = app->getTexture(setId, resId);

	lua_pushinteger(L, pTex->w);
	lua_pushinteger(L, pTex->h);

	return 2;
}

/** @brief テクスチャを描画する。
 * @details
 * @code
 * function graph:drawTexture(int setId, str resId,
 * 	int dx, int dy, bool lrInv = false, bool udInv = false,
 * 	int sx = 0, int sy = 0, int sw = -1, int sh = -1,
 * 	int cx = 0, int cy = 0, float angle = 0.0f,
 * 	float scaleX = 1.0f, float scaleY = 1.0f, float alpha = 1.0f)
 * end
 * @endcode
 * スクリーン座標 (dx, dy) に (cx, cy) が一致するように描画されます。
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	dx		描画先中心座標X
 * @param[in]	dy		描画先中心座標Y
 * @param[in]	lrInv	左右反転フラグ
 * @param[in]	udInv	上下反転フラグ
 * @param[in]	sx		テクスチャから切り出す際の左上座標X
 * @param[in]	sy		テクスチャから切り出す際の左上座標Y
 * @param[in]	sw		切り出しサイズX(-1でテクスチャサイズ)
 * @param[in]	sh		切り出しサイズY(-1でテクスチャサイズ)
 * @param[in]	cx		(sx, sy)基準の描画元中心座標X
 * @param[in]	cy		(sx, sy)基準の描画元中心座標Y
 * @param[in]	angle	回転角(rad)
 * @param[in]	scaleX	拡大率X
 * @param[in]	scaleY	拡大率Y
 * @param[in]	alpha	透明度(0.0 - 1.0)
 * @return				なし
 *
 * @sa graphics::DGraphics::drawTexture()
 * @bug sw, sh のデフォルトが0になっている。
 */
int graph::drawTexture(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, graph_RawFieldName);
	int setId = getInt(L, 2, 0);
	const char *resId = luaL_checkstring(L, 3);
	int dx = getInt(L, 4);
	int dy = getInt(L, 5);

	bool lrInv = lua_toboolean(L, 6) != 0;
	bool udInv = lua_toboolean(L, 7) != 0;
	int sx = getOptInt(L, 8, 0);
	int sy = getOptInt(L, 9, 0);
	int sw = getOptInt(L, 10, 0);
	int sh = getOptInt(L, 11, 0);
	int cx = getOptInt(L, 12, 0);
	int cy = getOptInt(L, 13, 0);
	float angle = getOptFloat(L, 14, 0.0f);
	float scaleX = getOptFloat(L, 15, 1.0f);
	float scaleY = getOptFloat(L, 16, 1.0f);
	float alpha = getOptFloat(L, 17, 1.0f);

	const auto &pTex = app->getTexture(setId, resId);
	app->graph().drawTexture(pTex, dx, dy, lrInv, udInv, sx, sy, sw, sh, cx, cy,
		angle, scaleX, scaleY, alpha);

	return 0;
}

/** @brief 文字列を描画する。
 * @details
 * @code
 * function graph:drawString(int setId, str resId, str str, int dx, int dy,
 * 	int color = 0x000000, int ajustX = 0,
 * 	float scaleX = 1.0f, float scaleY = 1.0f, float alpha = 1.0f)
 * end
 * @endcode
 * スクリーン座標 (dx, dy) に (cx, cy) が一致するように描画されます。
 *
 * @param[in]	setId	リソースセットID(整数値)
 * @param[in]	resId	リソースID(文字列)
 * @param[in]	str		描画する文字列
 * @param[in]	dx		描画先座標X
 * @param[in]	dy		描画先座標Y
 * @param[in]	color	文字色 (0xRRGGBB)
 * @param[in]	ajustX	文字間隔調整用X移動量
 * @param[in]	scaleX	拡大率X
 * @param[in]	scaleY	拡大率Y
 * @param[in]	alpha	透明度(0.0 - 1.0)
 * @return				なし
 *
 * @sa graphics::DGraphics::drawString()
 */
int graph::drawString(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, graph_RawFieldName);
	int setId = getInt(L, 2, 0);
	const char *resId = luaL_checkstring(L, 3);
	const char *str = luaL_checkstring(L, 4);
	int dx = getInt(L, 5);
	int dy = getInt(L, 6);

	int color = getOptInt(L, 7, 0x000000);
	int ajustX = getOptInt(L, 8, 0);
	float scaleX = getOptFloat(L, 9, 1.0f);
	float scaleY = getOptFloat(L, 10, 1.0f);
	float alpha = getOptFloat(L, 11, 1.0f);

	const auto &pFont = app->getFont(setId, resId);
	app->graph().drawString(pFont, util::utf82wc(str).get(), dx, dy,
		color, ajustX, scaleX, scaleY, alpha);

	return 0;
}

///////////////////////////////////////////////////////////////////////////////
// "sound" table
///////////////////////////////////////////////////////////////////////////////

/** @brief BGM 再生を開始する。
 * @details
 * @code
 * function sound:playBgm(str path)
 * end
 * @endcode
 *
 * @param[in]	path	BGM oggファイルのパス
 * @return				なし
 *
 * @todo 多分リソースベースのインタフェースに変えます。
 */
int sound::playBgm(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, sound_RawFieldName);
	const char *path = luaL_checkstring(L, 2);

	app->sound().playBgm(util::utf82wc(path).get());

	return 0;
}

/** @brief BGM 再生を停止する。
 * @details
 * @code
 * function sound:stopBgm()
 * end
 * @endcode
 *
 * @return				なし
 */
int sound::stopBgm(lua_State *L)
{
	auto *app = getPtrFromSelf<framework::Application>(L, sound_RawFieldName);

	app->sound().stopBgm();

	return 0;
}

}
}
}
<|endoftext|>


<commit_before><commit_msg>Use O_CLOEXEC for open instead of separate fcntl(2) call.<commit_after><|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stx/exception.h>
#include <stx/inspect.h>
#include "stx/logging.h"
#include <stx/wallclock.h>
#include <stx/assets.h>
#include <stx/http/cookies.h>
#include "stx/http/httprequest.h"
#include "stx/http/httpresponse.h"
#include "stx/http/status.h"
#include "stx/random.h"
#include "stx/json/json.h"
#include "stx/json/jsonrpcrequest.h"
#include "stx/json/jsonrpcresponse.h"
#include "zbase/tracker/TrackerServlet.h"
#include "zbase/tracker/ztrackid.h"

using namespace stx;

namespace zbase {

const unsigned char pixel_gif[42] = {
  0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x21, 0xf9, 0x04, 0x01, 0x00,
  0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
  0x00, 0x02, 0x01, 0x44, 0x00, 0x3b
};

TrackerServlet::TrackerServlet(
    feeds::RemoteFeedWriter* tracker_log_feed) :
    tracker_log_feed_(tracker_log_feed) {
  exportStats("/ztracker/global");
  //exportStats(StringUtil::format("/ztracker/by-host/$0", cmHostname()));
}

void TrackerServlet::exportStats(const std::string& prefix) {
  exportStat(
      StringUtil::format("$0/$1", prefix, "rpc_requests_total"),
      &stat_rpc_requests_total_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "rpc_errors_total"),
      &stat_rpc_errors_total_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_total"),
      &stat_loglines_total_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_versiontooold"),
      &stat_loglines_versiontooold_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_invalid"),
      &stat_loglines_invalid_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_written_success"),
      &stat_loglines_written_success_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_written_failure"),
      &stat_loglines_written_failure_,
      stx::stats::ExportMode::EXPORT_DELTA);
}

void TrackerServlet::handleHTTPRequest(
    stx::http::HTTPRequest* request,
    stx::http::HTTPResponse* response) {
  stx::URI uri(request->uri());

  static const String kJSAPIPrefix = "/api-";
  static const String kJSAPISuffix = ".js";
  if (StringUtil::beginsWith(uri.path(), kJSAPIPrefix) &&
      StringUtil::endsWith(uri.path(), kJSAPISuffix)) {
    auto ztrackid = uri.path().substr(
        kJSAPIPrefix.size(),
        uri.path().size() - kJSAPIPrefix.size() - kJSAPISuffix.size());
    auto customer = ztrackid_decode(ztrackid);
    iputs("get pixel for $0 => $1", ztrackid, customer);

    response->setStatus(stx::http::kStatusOK);
    response->addHeader("Content-Type", "application/javascript");
    response->addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    response->addHeader("Pragma", "no-cache");
    response->addHeader("Expires", "0");
    response->addBody(Assets::getAsset("zbase/tracker/track.js"));
    return;
  }

  static const String kPushAPIPrefix = "/push-";
  if (StringUtil::beginsWith(uri.path(), kPushAPIPrefix)) {
    auto ztrackid = uri.path().substr(
        kPushAPIPrefix.size(),
        uri.path().size() - kPushAPIPrefix.size());
    auto customer = ztrackid_decode(ztrackid);

    try {
      pushEvent(customer, uri.query());
    } catch (const std::exception& e) {
      auto msg = stx::StringUtil::format(
          "invalid tracking pixel url: $0",
          uri.query());

      stx::logDebug("cm.frontend", e, msg);
    }

    response->setStatus(stx::http::kStatusOK);
    response->addHeader("Content-Type", "image/gif");
    response->addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    response->addHeader("Pragma", "no-cache");
    response->addHeader("Expires", "0");
    response->addBody((void *) &pixel_gif, sizeof(pixel_gif));
    return;
  }

  response->setStatus(stx::http::kStatusNotFound);
  response->addBody("not found");
}

void TrackerServlet::pushEvent(
    const String& customer,
    const std::string& ev) {
  iputs("incoming logline: $0 => $1", customer, ev);
  //stx::URI::ParamList params;
  //stx::URI::parseQueryString(logline, &params);

  //stat_loglines_total_.incr(1);

  //std::string pixel_ver;
  //if (!stx::URI::getParam(params, "v", &pixel_ver)) {
  //  stat_loglines_invalid_.incr(1);
  //  RAISE(kRuntimeError, "missing v parameter");
  //}

  //try {
  //  if (std::stoi(pixel_ver) < kMinPixelVersion) {
  //    stat_loglines_versiontooold_.incr(1);
  //    stat_loglines_invalid_.incr(1);
  //    RAISEF(kRuntimeError, "pixel version too old: $0", pixel_ver);
  //  }
  //} catch (const std::exception& e) {
  //  stat_loglines_invalid_.incr(1);
  //  RAISEF(kRuntimeError, "invalid pixel version: $0", pixel_ver);
  //}

  ////auto feedline = stx::StringUtil::format(
  ////    "$0|$1|$2",
  ////    customer->key(),
  ////    stx::WallClock::unixSeconds(),
  ////    logline);

  ////tracker_log_feed_->appendEntry(feedline);
}

} // namespace zbase
<commit_msg>upload via ajax<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stx/exception.h>
#include <stx/inspect.h>
#include "stx/logging.h"
#include <stx/wallclock.h>
#include <stx/assets.h>
#include <stx/http/cookies.h>
#include "stx/http/httprequest.h"
#include "stx/http/httpresponse.h"
#include "stx/http/status.h"
#include "stx/random.h"
#include "stx/json/json.h"
#include "stx/json/jsonrpcrequest.h"
#include "stx/json/jsonrpcresponse.h"
#include "zbase/tracker/TrackerServlet.h"
#include "zbase/tracker/ztrackid.h"

using namespace stx;

namespace zbase {

const unsigned char pixel_gif[42] = {
  0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x21, 0xf9, 0x04, 0x01, 0x00,
  0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
  0x00, 0x02, 0x01, 0x44, 0x00, 0x3b
};

TrackerServlet::TrackerServlet(
    feeds::RemoteFeedWriter* tracker_log_feed) :
    tracker_log_feed_(tracker_log_feed) {
  exportStats("/ztracker/global");
  //exportStats(StringUtil::format("/ztracker/by-host/$0", cmHostname()));
}

void TrackerServlet::exportStats(const std::string& prefix) {
  exportStat(
      StringUtil::format("$0/$1", prefix, "rpc_requests_total"),
      &stat_rpc_requests_total_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "rpc_errors_total"),
      &stat_rpc_errors_total_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_total"),
      &stat_loglines_total_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_versiontooold"),
      &stat_loglines_versiontooold_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_invalid"),
      &stat_loglines_invalid_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_written_success"),
      &stat_loglines_written_success_,
      stx::stats::ExportMode::EXPORT_DELTA);

  exportStat(
      StringUtil::format("$0/$1", prefix, "loglines_written_failure"),
      &stat_loglines_written_failure_,
      stx::stats::ExportMode::EXPORT_DELTA);
}

void TrackerServlet::handleHTTPRequest(
    stx::http::HTTPRequest* request,
    stx::http::HTTPResponse* response) {
  stx::URI uri(request->uri());

  response->addHeader("Access-Control-Allow-Origin", "*"); // FIXME
  response->addHeader("Access-Control-Allow-Methods", "GET, POST");

  if (request->method() == http::HTTPMessage::M_OPTIONS) {
    response->setStatus(http::kStatusOK);
    return;
  }

  static const String kJSAPIPrefix = "/api-";
  static const String kJSAPISuffix = ".js";
  if (StringUtil::beginsWith(uri.path(), kJSAPIPrefix) &&
      StringUtil::endsWith(uri.path(), kJSAPISuffix)) {
    auto ztrackid = uri.path().substr(
        kJSAPIPrefix.size(),
        uri.path().size() - kJSAPIPrefix.size() - kJSAPISuffix.size());
    auto customer = ztrackid_decode(ztrackid);
    iputs("get pixel for $0 => $1", ztrackid, customer);

    response->setStatus(stx::http::kStatusOK);
    response->addHeader("Content-Type", "application/javascript");
    response->addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    response->addHeader("Pragma", "no-cache");
    response->addHeader("Expires", "0");
    response->addBody(Assets::getAsset("zbase/tracker/track.js"));
    return;
  }

  static const String kPushAPIPrefix = "/push-";
  if (StringUtil::beginsWith(uri.path(), kPushAPIPrefix)) {
    auto ztrackid = uri.path().substr(
        kPushAPIPrefix.size(),
        uri.path().size() - kPushAPIPrefix.size());
    auto customer = ztrackid_decode(ztrackid);

    String pixeldata;
    if (request->method() == http::HTTPMessage::M_POST) {
      pixeldata = request->body().toString();
    } else {
      pixeldata = uri.query();
    }

    try {
      pushEvent(customer, pixeldata);
    } catch (const std::exception& e) {
      auto msg = stx::StringUtil::format(
          "invalid tracking pixel data: $0",
          pixeldata);

      stx::logDebug("cm.frontend", e, msg);
    }

    response->setStatus(stx::http::kStatusOK);
    response->addHeader("Content-Type", "image/gif");
    response->addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    response->addHeader("Pragma", "no-cache");
    response->addHeader("Expires", "0");
    response->addBody((void *) &pixel_gif, sizeof(pixel_gif));
    return;
  }

  response->setStatus(stx::http::kStatusNotFound);
  response->addBody("not found");
}

void TrackerServlet::pushEvent(
    const String& customer,
    const std::string& ev) {
  iputs("incoming logline: $0 => $1", customer, ev);
  //stx::URI::ParamList params;
  //stx::URI::parseQueryString(logline, &params);

  //stat_loglines_total_.incr(1);

  //std::string pixel_ver;
  //if (!stx::URI::getParam(params, "v", &pixel_ver)) {
  //  stat_loglines_invalid_.incr(1);
  //  RAISE(kRuntimeError, "missing v parameter");
  //}

  //try {
  //  if (std::stoi(pixel_ver) < kMinPixelVersion) {
  //    stat_loglines_versiontooold_.incr(1);
  //    stat_loglines_invalid_.incr(1);
  //    RAISEF(kRuntimeError, "pixel version too old: $0", pixel_ver);
  //  }
  //} catch (const std::exception& e) {
  //  stat_loglines_invalid_.incr(1);
  //  RAISEF(kRuntimeError, "invalid pixel version: $0", pixel_ver);
  //}

  ////auto feedline = stx::StringUtil::format(
  ////    "$0|$1|$2",
  ////    customer->key(),
  ////    stx::WallClock::unixSeconds(),
  ////    logline);

  ////tracker_log_feed_->appendEntry(feedline);
}

} // namespace zbase
<|endoftext|>