<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * 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 <rtl/locale.h>
#include <osl/nlsupport.h>
#include <osl/process.h>

#include <util.hxx>

#include <stdio.h>

#include <com/sun/star/registry/XImplementationRegistration.hpp>
#include <com/sun/star/security/KeyUsage.hpp>
#include <cppuhelper/bootstrap.hxx>
#include <xmlsecurity/biginteger.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/streamhelper.hxx>

#include <rtl/ustrbuf.hxx>
#include <tools/string.hxx>

namespace cssu = com::sun::star::uno;
namespace cssl = com::sun::star::lang;
namespace cssxc = com::sun::star::xml::crypto;
namespace cssi = com::sun::star::io;

using namespace ::com::sun::star;

/** convert util::DateTime to ISO Date String */
void convertDateTime( ::rtl::OUStringBuffer& rBuffer,
    const com::sun::star::util::DateTime& rDateTime )
{
    String aString( String::CreateFromInt32( rDateTime.Year ) );
    aString += '-';
    if( rDateTime.Month < 10 )
        aString += '0';
    aString += String::CreateFromInt32( rDateTime.Month );
    aString += '-';
    if( rDateTime.Day < 10 )
        aString += '0';
    aString += String::CreateFromInt32( rDateTime.Day );

    if( rDateTime.Seconds != 0 ||
        rDateTime.Minutes != 0 ||
        rDateTime.Hours   != 0 )
    {
        aString += 'T';
        if( rDateTime.Hours < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Hours );
        aString += ':';
        if( rDateTime.Minutes < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Minutes );
        aString += ':';
        if( rDateTime.Seconds < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Seconds );
        if ( rDateTime.HundredthSeconds > 0)
        {
            aString += ',';
            if (rDateTime.HundredthSeconds < 10)
                aString += '0';
            aString += String::CreateFromInt32( rDateTime.HundredthSeconds );
        }
    }

    rBuffer.append( aString );
}

::rtl::OUString printHexString(cssu::Sequence< sal_Int8 > data)
{
    int length = data.getLength();
    ::rtl::OUString result;

    char number[4];
    for (int j=0; j<length; j++)
    {
        sprintf(number, "%02X ", (unsigned char)data[j]);
        result += rtl::OUString::createFromAscii( number );
    }

    return result;
}

::rtl::OUString getSignatureInformation(
    const SignatureInformation& infor,
    cssu::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment >& xSecurityEnvironment )
{
    char* status[50] = {
        "STATUS_UNKNOWN",
        "OPERATION_SUCCEEDED",
        "RUNTIMEERROR_FAILED",
        "ENGINE_FAILED",
        "MALLOC_FAILED",
        "STRDUP_FAILED",
        "CRYPTO_FAILED",
        "XML_FAILED",
        "XSLT_FAILED",
        "IO_FAILED",
        "DISABLED",
        "NOT_IMPLEMENTED",
        "INVALID_SIZE",
        "INVALID_DATA",
        "INVALID_RESULT",
        "INVALID_TYPE",
        "INVALID_OPERATION",
        "INVALID_STATUS",
        "INVALID_FORMAT",
        "DATA_NOT_MATCH",
        "INVALID_NODE",
        "INVALID_NODE_CONTENT",
        "INVALID_NODE_ATTRIBUTE",
        "MISSING_NODE_ATTRIBUTE",
        "NODE_ALREADY_PRESENT",
        "UNEXPECTED_NODE",
        "NODE_NOT_FOUND",
        "INVALID_TRANSFORM",
        "INVALID_TRANSFORM_KEY",
        "INVALID_URI_TYPE",
        "TRANSFORM_SAME_DOCUMENT_REQUIRED",
        "TRANSFORM_DISABLED",
        "INVALID_KEY_DATA",
        "KEY_DATA_NOT_FOUND",
        "KEY_DATA_ALREADY_EXIST",
        "INVALID_KEY_DATA_SIZE",
        "KEY_NOT_FOUND",
        "KEYDATA_DISABLED",
        "MAX_RETRIEVALS_LEVEL",
        "MAX_RETRIEVAL_TYPE_MISMATCH",
        "MAX_ENCKEY_LEVEL",
        "CERT_VERIFY_FAILED",
        "CERT_NOT_FOUND",
        "CERT_REVOKED",
        "CERT_ISSUER_FAILED",
        "CERT_NOT_YET_VALID",
        "CERT_HAS_EXPIRED",
        "DSIG_NO_REFERENCES",
        "DSIG_INVALID_REFERENCE",
        "ASSERTION"};

    rtl::OUString result;

    result += rtl::OUString::createFromAscii( "Security Id : " )
        +rtl::OUString::valueOf(infor.nSecurityId)
        +rtl::OUString::createFromAscii( "\n" );
    result += rtl::OUString::createFromAscii( "Status : [" )
        +rtl::OUString::valueOf((sal_Int32)(infor.nStatus))
        +rtl::OUString::createFromAscii( "] " )
        +rtl::OUString::createFromAscii(status[infor.nStatus])
        +rtl::OUString::createFromAscii( "\n" );

    const SignatureReferenceInformations& rInfors = infor.vSignatureReferenceInfors;
    int i;
    int size = rInfors.size();

    result += rtl::OUString::createFromAscii( "--References :\n" );
    for (i=0; i<size; i++)
    {
            result += rtl::OUString::createFromAscii( "---URI : " );
        result += rInfors[i].ouURI;
        result += rtl::OUString::createFromAscii( "\n" );
            result += rtl::OUString::createFromAscii( "---DigestValue : " );
        result += rInfors[i].ouDigestValue;
        result += rtl::OUString::createFromAscii( "\n" );
    }

        if (infor.ouX509IssuerName.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509IssuerName :\n" );
            result += infor.ouX509IssuerName;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouX509SerialNumber.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509SerialNumber :\n" );
            result += infor.ouX509SerialNumber;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouX509Certificate.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509Certificate :\n" );
            result += infor.ouX509Certificate;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouSignatureValue.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--SignatureValue :\n" );
            result += infor.ouSignatureValue;
            result += rtl::OUString::createFromAscii( "\n" );
        }

           result += rtl::OUString::createFromAscii( "--Date :\n" );

    ::rtl::OUStringBuffer buffer;
    convertDateTime( buffer, infor.stDateTime );
    result += buffer.makeStringAndClear();
           result += rtl::OUString::createFromAscii( "\n" );

        if (infor.ouX509IssuerName.getLength()>0 && infor.ouX509SerialNumber.getLength()>0 && xSecurityEnvironment.is())
        {
            result += rtl::OUString::createFromAscii( "--Certificate Path :\n" );
            cssu::Reference< ::com::sun::star::security::XCertificate > xCert = xSecurityEnvironment->getCertificate( infor.ouX509IssuerName, numericStringToBigInteger(infor.ouX509SerialNumber) );
            cssu::Sequence < cssu::Reference< ::com::sun::star::security::XCertificate > > xCertPath;
            if(! xCert.is() )
            {
                fprintf(stdout , " xCert is NULL , so can not buildCertificatePath\n");
                return result ;
            }
            else
            {
                xCertPath = xSecurityEnvironment->buildCertificatePath( xCert ) ;
            }

        for( int i = 0; i < xCertPath.getLength(); i++ )
        {
            result += xCertPath[i]->getSubjectName();
                    result += rtl::OUString::createFromAscii( "\n    Subject public key algorithm : " );
                    result += xCertPath[i]->getSubjectPublicKeyAlgorithm();
                    result += rtl::OUString::createFromAscii( "\n    Signature algorithm : " );
                    result += xCertPath[i]->getSignatureAlgorithm();

                    result += rtl::OUString::createFromAscii( "\n    Subject public key value : " );
                    cssu::Sequence< sal_Int8 > keyValue = xCertPath[i]->getSubjectPublicKeyValue();
                    result += printHexString(keyValue);

                    result += rtl::OUString::createFromAscii( "\n    Thumbprint (SHA1) : " );
                    cssu::Sequence< sal_Int8 > SHA1Thumbprint = xCertPath[i]->getSHA1Thumbprint();
                    result += printHexString(SHA1Thumbprint);

                    result += rtl::OUString::createFromAscii( "\n    Thumbprint (MD5) : " );
                    cssu::Sequence< sal_Int8 > MD5Thumbprint = xCertPath[i]->getMD5Thumbprint();
                    result += printHexString(MD5Thumbprint);

                    result += rtl::OUString::createFromAscii( "\n  <<\n" );
        }

                   result += rtl::OUString::createFromAscii( "\n    Key Usage : " );
                   sal_Int32 usage = xCert->getCertificateUsage();

                   if (usage & ::com::sun::star::security::KeyUsage::DIGITAL_SIGNATURE)
                   {
                       result += rtl::OUString::createFromAscii( "DIGITAL_SIGNATURE " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::NON_REPUDIATION)
                   {
                       result += rtl::OUString::createFromAscii( "NON_REPUDIATION " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_ENCIPHERMENT)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_ENCIPHERMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::DATA_ENCIPHERMENT)
                   {
                       result += rtl::OUString::createFromAscii( "DATA_ENCIPHERMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_AGREEMENT)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_AGREEMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_CERT_SIGN)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_CERT_SIGN " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::CRL_SIGN)
                   {
                       result += rtl::OUString::createFromAscii( "CRL_SIGN " );
                   }

                   result += rtl::OUString::createFromAscii( "\n" );
        }

    result += rtl::OUString::createFromAscii( "\n" );
    return result;
}

::rtl::OUString getSignatureInformations(
    const SignatureInformations& SignatureInformations,
    cssu::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > xSecurityEnvironment )
{
    rtl::OUString result;
    int i;
    int size = SignatureInformations.size();

    for (i=0; i<size; i++)
    {
        const SignatureInformation& infor = SignatureInformations[i];
        result += getSignatureInformation( infor, xSecurityEnvironment );
    }

    result += rtl::OUString::createFromAscii( "\n" );

    return result;
}

::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificate >
    getCertificateFromEnvironment( ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment >  xSecurityEnvironment , BOOL nType)
{
    cssu::Sequence< cssu::Reference< ::com::sun::star::security::XCertificate > > xPersonalCerts ;
    int length = 0;
    int i;

    // add By CP
    sal_uInt16 encoding ;
    rtl_Locale *pLocale = NULL ;
    osl_getProcessLocale( &pLocale ) ;
    encoding = osl_getTextEncodingFromLocale( pLocale ) ;
    // CP end

    if( nType != FALSE )
        xPersonalCerts = xSecurityEnvironment->getPersonalCertificates() ;
    else
        return NULL; // not support then;

    length = xPersonalCerts.getLength();
    if(length == 0)
    {
        fprintf( stdout, "\nNo certificate found!\n" ) ;
        return NULL;
    }

    fprintf( stdout, "\nSelect a certificate:\n" ) ;
    for( i = 0; i < length; i ++ )
    {
        rtl::OUString xxxIssuer;
        rtl::OUString xxxSubject;
        rtl::OString yyyIssuer;
        rtl::OString yyySubject;

        xxxIssuer=xPersonalCerts[i]->getIssuerName();
        yyyIssuer=rtl::OUStringToOString( xxxIssuer, encoding );

        xxxSubject=xPersonalCerts[i]->getSubjectName();
        yyySubject=rtl::OUStringToOString( xxxSubject, encoding );

        fprintf( stdout, "\n%d:\nsubject=[%s]\nissuer=[%s]\n",
            i+1,
            yyySubject.getStr(),
            yyyIssuer.getStr());
    }

    int sel = QuerySelectNumber( 1, length ) -1;
    return xPersonalCerts[sel] ;
}

void QueryPrintSignatureDetails( const SignatureInformations& SignatureInformations, ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > rSecEnv )
{
    char cShowDetails;
    fprintf( stdout, "\nDisplay details (y/n) [y]?" );
    fflush(stdin);
    fscanf( stdin, "%c", &cShowDetails);
    if ( cShowDetails == 'y' )
    {
        rtl_Locale *pLocale = NULL ;
        osl_getProcessLocale( &pLocale ) ;
        sal_uInt16 encoding = osl_getTextEncodingFromLocale( pLocale ) ;

        fprintf( stdout, "------------- Signature details START -------------\n" );
        fprintf( stdout, "%s",
            rtl::OUStringToOString(
                getSignatureInformations( SignatureInformations, rSecEnv),
                encoding).getStr());

        fprintf( stdout, "------------- Signature details END -------------\n" );
    }
}

int QuerySelectNumber( int nMin, int nMax )
{
    fprintf( stdout, "\n" ) ;
    int sel = 0;
    do
    {
        fprintf( stdout, "\nSelect <%d-%d>:", nMin, nMax ) ;
        fflush(stdin);
        fscanf( stdin, "%d", &sel ) ;
    } while( ( sel < nMin ) || ( sel > nMax ) );

    return sel;
}

long QueryVerifySignature()
{
    char answer;
    fprintf( stdout, "\nFound a signature - verify this one (y/n) [y]?" );
    fflush(stdin);
    fscanf( stdin, "%c", &answer);
    return  (answer == 'n')?0:1;
}
<commit_msg>cmcfixes78: #i111733# fflush on stdin<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * 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 <rtl/locale.h>
#include <osl/nlsupport.h>
#include <osl/process.h>

#include <util.hxx>

#include <stdio.h>

#include <com/sun/star/registry/XImplementationRegistration.hpp>
#include <com/sun/star/security/KeyUsage.hpp>
#include <cppuhelper/bootstrap.hxx>
#include <xmlsecurity/biginteger.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/streamhelper.hxx>

#include <rtl/ustrbuf.hxx>
#include <tools/string.hxx>

namespace cssu = com::sun::star::uno;
namespace cssl = com::sun::star::lang;
namespace cssxc = com::sun::star::xml::crypto;
namespace cssi = com::sun::star::io;

using namespace ::com::sun::star;

/** convert util::DateTime to ISO Date String */
void convertDateTime( ::rtl::OUStringBuffer& rBuffer,
    const com::sun::star::util::DateTime& rDateTime )
{
    String aString( String::CreateFromInt32( rDateTime.Year ) );
    aString += '-';
    if( rDateTime.Month < 10 )
        aString += '0';
    aString += String::CreateFromInt32( rDateTime.Month );
    aString += '-';
    if( rDateTime.Day < 10 )
        aString += '0';
    aString += String::CreateFromInt32( rDateTime.Day );

    if( rDateTime.Seconds != 0 ||
        rDateTime.Minutes != 0 ||
        rDateTime.Hours   != 0 )
    {
        aString += 'T';
        if( rDateTime.Hours < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Hours );
        aString += ':';
        if( rDateTime.Minutes < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Minutes );
        aString += ':';
        if( rDateTime.Seconds < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Seconds );
        if ( rDateTime.HundredthSeconds > 0)
        {
            aString += ',';
            if (rDateTime.HundredthSeconds < 10)
                aString += '0';
            aString += String::CreateFromInt32( rDateTime.HundredthSeconds );
        }
    }

    rBuffer.append( aString );
}

::rtl::OUString printHexString(cssu::Sequence< sal_Int8 > data)
{
    int length = data.getLength();
    ::rtl::OUString result;

    char number[4];
    for (int j=0; j<length; j++)
    {
        sprintf(number, "%02X ", (unsigned char)data[j]);
        result += rtl::OUString::createFromAscii( number );
    }

    return result;
}

::rtl::OUString getSignatureInformation(
    const SignatureInformation& infor,
    cssu::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment >& xSecurityEnvironment )
{
    char* status[50] = {
        "STATUS_UNKNOWN",
        "OPERATION_SUCCEEDED",
        "RUNTIMEERROR_FAILED",
        "ENGINE_FAILED",
        "MALLOC_FAILED",
        "STRDUP_FAILED",
        "CRYPTO_FAILED",
        "XML_FAILED",
        "XSLT_FAILED",
        "IO_FAILED",
        "DISABLED",
        "NOT_IMPLEMENTED",
        "INVALID_SIZE",
        "INVALID_DATA",
        "INVALID_RESULT",
        "INVALID_TYPE",
        "INVALID_OPERATION",
        "INVALID_STATUS",
        "INVALID_FORMAT",
        "DATA_NOT_MATCH",
        "INVALID_NODE",
        "INVALID_NODE_CONTENT",
        "INVALID_NODE_ATTRIBUTE",
        "MISSING_NODE_ATTRIBUTE",
        "NODE_ALREADY_PRESENT",
        "UNEXPECTED_NODE",
        "NODE_NOT_FOUND",
        "INVALID_TRANSFORM",
        "INVALID_TRANSFORM_KEY",
        "INVALID_URI_TYPE",
        "TRANSFORM_SAME_DOCUMENT_REQUIRED",
        "TRANSFORM_DISABLED",
        "INVALID_KEY_DATA",
        "KEY_DATA_NOT_FOUND",
        "KEY_DATA_ALREADY_EXIST",
        "INVALID_KEY_DATA_SIZE",
        "KEY_NOT_FOUND",
        "KEYDATA_DISABLED",
        "MAX_RETRIEVALS_LEVEL",
        "MAX_RETRIEVAL_TYPE_MISMATCH",
        "MAX_ENCKEY_LEVEL",
        "CERT_VERIFY_FAILED",
        "CERT_NOT_FOUND",
        "CERT_REVOKED",
        "CERT_ISSUER_FAILED",
        "CERT_NOT_YET_VALID",
        "CERT_HAS_EXPIRED",
        "DSIG_NO_REFERENCES",
        "DSIG_INVALID_REFERENCE",
        "ASSERTION"};

    rtl::OUString result;

    result += rtl::OUString::createFromAscii( "Security Id : " )
        +rtl::OUString::valueOf(infor.nSecurityId)
        +rtl::OUString::createFromAscii( "\n" );
    result += rtl::OUString::createFromAscii( "Status : [" )
        +rtl::OUString::valueOf((sal_Int32)(infor.nStatus))
        +rtl::OUString::createFromAscii( "] " )
        +rtl::OUString::createFromAscii(status[infor.nStatus])
        +rtl::OUString::createFromAscii( "\n" );

    const SignatureReferenceInformations& rInfors = infor.vSignatureReferenceInfors;
    int i;
    int size = rInfors.size();

    result += rtl::OUString::createFromAscii( "--References :\n" );
    for (i=0; i<size; i++)
    {
            result += rtl::OUString::createFromAscii( "---URI : " );
        result += rInfors[i].ouURI;
        result += rtl::OUString::createFromAscii( "\n" );
            result += rtl::OUString::createFromAscii( "---DigestValue : " );
        result += rInfors[i].ouDigestValue;
        result += rtl::OUString::createFromAscii( "\n" );
    }

        if (infor.ouX509IssuerName.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509IssuerName :\n" );
            result += infor.ouX509IssuerName;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouX509SerialNumber.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509SerialNumber :\n" );
            result += infor.ouX509SerialNumber;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouX509Certificate.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509Certificate :\n" );
            result += infor.ouX509Certificate;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouSignatureValue.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--SignatureValue :\n" );
            result += infor.ouSignatureValue;
            result += rtl::OUString::createFromAscii( "\n" );
        }

           result += rtl::OUString::createFromAscii( "--Date :\n" );

    ::rtl::OUStringBuffer buffer;
    convertDateTime( buffer, infor.stDateTime );
    result += buffer.makeStringAndClear();
           result += rtl::OUString::createFromAscii( "\n" );

        if (infor.ouX509IssuerName.getLength()>0 && infor.ouX509SerialNumber.getLength()>0 && xSecurityEnvironment.is())
        {
            result += rtl::OUString::createFromAscii( "--Certificate Path :\n" );
            cssu::Reference< ::com::sun::star::security::XCertificate > xCert = xSecurityEnvironment->getCertificate( infor.ouX509IssuerName, numericStringToBigInteger(infor.ouX509SerialNumber) );
            cssu::Sequence < cssu::Reference< ::com::sun::star::security::XCertificate > > xCertPath;
            if(! xCert.is() )
            {
                fprintf(stdout , " xCert is NULL , so can not buildCertificatePath\n");
                return result ;
            }
            else
            {
                xCertPath = xSecurityEnvironment->buildCertificatePath( xCert ) ;
            }

        for( int i = 0; i < xCertPath.getLength(); i++ )
        {
            result += xCertPath[i]->getSubjectName();
                    result += rtl::OUString::createFromAscii( "\n    Subject public key algorithm : " );
                    result += xCertPath[i]->getSubjectPublicKeyAlgorithm();
                    result += rtl::OUString::createFromAscii( "\n    Signature algorithm : " );
                    result += xCertPath[i]->getSignatureAlgorithm();

                    result += rtl::OUString::createFromAscii( "\n    Subject public key value : " );
                    cssu::Sequence< sal_Int8 > keyValue = xCertPath[i]->getSubjectPublicKeyValue();
                    result += printHexString(keyValue);

                    result += rtl::OUString::createFromAscii( "\n    Thumbprint (SHA1) : " );
                    cssu::Sequence< sal_Int8 > SHA1Thumbprint = xCertPath[i]->getSHA1Thumbprint();
                    result += printHexString(SHA1Thumbprint);

                    result += rtl::OUString::createFromAscii( "\n    Thumbprint (MD5) : " );
                    cssu::Sequence< sal_Int8 > MD5Thumbprint = xCertPath[i]->getMD5Thumbprint();
                    result += printHexString(MD5Thumbprint);

                    result += rtl::OUString::createFromAscii( "\n  <<\n" );
        }

                   result += rtl::OUString::createFromAscii( "\n    Key Usage : " );
                   sal_Int32 usage = xCert->getCertificateUsage();

                   if (usage & ::com::sun::star::security::KeyUsage::DIGITAL_SIGNATURE)
                   {
                       result += rtl::OUString::createFromAscii( "DIGITAL_SIGNATURE " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::NON_REPUDIATION)
                   {
                       result += rtl::OUString::createFromAscii( "NON_REPUDIATION " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_ENCIPHERMENT)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_ENCIPHERMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::DATA_ENCIPHERMENT)
                   {
                       result += rtl::OUString::createFromAscii( "DATA_ENCIPHERMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_AGREEMENT)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_AGREEMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_CERT_SIGN)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_CERT_SIGN " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::CRL_SIGN)
                   {
                       result += rtl::OUString::createFromAscii( "CRL_SIGN " );
                   }

                   result += rtl::OUString::createFromAscii( "\n" );
        }

    result += rtl::OUString::createFromAscii( "\n" );
    return result;
}

::rtl::OUString getSignatureInformations(
    const SignatureInformations& SignatureInformations,
    cssu::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > xSecurityEnvironment )
{
    rtl::OUString result;
    int i;
    int size = SignatureInformations.size();

    for (i=0; i<size; i++)
    {
        const SignatureInformation& infor = SignatureInformations[i];
        result += getSignatureInformation( infor, xSecurityEnvironment );
    }

    result += rtl::OUString::createFromAscii( "\n" );

    return result;
}

::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificate >
    getCertificateFromEnvironment( ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment >  xSecurityEnvironment , BOOL nType)
{
    cssu::Sequence< cssu::Reference< ::com::sun::star::security::XCertificate > > xPersonalCerts ;
    int length = 0;
    int i;

    // add By CP
    sal_uInt16 encoding ;
    rtl_Locale *pLocale = NULL ;
    osl_getProcessLocale( &pLocale ) ;
    encoding = osl_getTextEncodingFromLocale( pLocale ) ;
    // CP end

    if( nType != FALSE )
        xPersonalCerts = xSecurityEnvironment->getPersonalCertificates() ;
    else
        return NULL; // not support then;

    length = xPersonalCerts.getLength();
    if(length == 0)
    {
        fprintf( stdout, "\nNo certificate found!\n" ) ;
        return NULL;
    }

    fprintf( stdout, "\nSelect a certificate:\n" ) ;
    for( i = 0; i < length; i ++ )
    {
        rtl::OUString xxxIssuer;
        rtl::OUString xxxSubject;
        rtl::OString yyyIssuer;
        rtl::OString yyySubject;

        xxxIssuer=xPersonalCerts[i]->getIssuerName();
        yyyIssuer=rtl::OUStringToOString( xxxIssuer, encoding );

        xxxSubject=xPersonalCerts[i]->getSubjectName();
        yyySubject=rtl::OUStringToOString( xxxSubject, encoding );

        fprintf( stdout, "\n%d:\nsubject=[%s]\nissuer=[%s]\n",
            i+1,
            yyySubject.getStr(),
            yyyIssuer.getStr());
    }

    int sel = QuerySelectNumber( 1, length ) -1;
    return xPersonalCerts[sel] ;
}

void QueryPrintSignatureDetails( const SignatureInformations& SignatureInformations, ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > rSecEnv )
{
    char cShowDetails;
    fprintf( stdout, "\nDisplay details (y/n) [y]?" );
    fflush( stdout );
    fscanf( stdin, "%c", &cShowDetails);
    if ( cShowDetails == 'y' )
    {
        rtl_Locale *pLocale = NULL ;
        osl_getProcessLocale( &pLocale ) ;
        sal_uInt16 encoding = osl_getTextEncodingFromLocale( pLocale ) ;

        fprintf( stdout, "------------- Signature details START -------------\n" );
        fprintf( stdout, "%s",
            rtl::OUStringToOString(
                getSignatureInformations( SignatureInformations, rSecEnv),
                encoding).getStr());

        fprintf( stdout, "------------- Signature details END -------------\n" );
    }
}

int QuerySelectNumber( int nMin, int nMax )
{
    fprintf( stdout, "\n" ) ;
    int sel = 0;
    do
    {
        fprintf( stdout, "\nSelect <%d-%d>:", nMin, nMax ) ;
        fflush( stdout );
        fscanf( stdin, "%d", &sel ) ;
    } while( ( sel < nMin ) || ( sel > nMax ) );

    return sel;
}

long QueryVerifySignature()
{
    char answer;
    fprintf( stdout, "\nFound a signature - verify this one (y/n) [y]?" );
    fflush( stdout );
    fscanf( stdin, "%c", &answer);
    return  (answer == 'n')?0:1;
}
<|endoftext|>


<commit_before>/**
* @file       tutorial.cpp
*
* @brief      Simple tutorial program to illustrate Zerocoin usage.
*
* @author     Ian Miers, Christina Garman and Matthew Green
* @date       June 2013
*
* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
* @license    This project is released under the MIT license.
**/

using namespace std;

#include <string>
#include <iostream>
#include <fstream>
#include <curses.h>
#include <exception>
#include "Zerocoin.h"

#define COINS_TO_ACCUMULATE     5
#define DUMMY_TRANSACTION_HASH  0 // in real life these would be uint256 hashes
#define DUMMY_ACCUMULATOR_ID    0 // in real life these would be uint256 hashes

//
// We generated this for testing only. Don't use it in production!
//
#define TUTORIAL_TEST_MODULUS   "a8852ebf7c49f01cd196e35394f3b74dd86283a07f57e0a262928e7493d4a3961d93d93c90ea3369719641d626d28b9cddc6d9307b9aabdbffc40b6d6da2e329d079b4187ff784b2893d9f53e9ab913a04ff02668114695b07d8ce877c4c8cac1b12b9beff3c51294ebe349eca41c24cd32a6d09dd1579d3947e5c4dcc30b2090b0454edb98c6336e7571db09e0fdafbd68d8f0470223836e90666a5b143b73b9cd71547c917bf24c0efc86af2eba046ed781d9acb05c80f007ef5a0a5dfca23236f37e698e8728def12554bc80f294f71c040a88eff144d130b24211016a97ce0f5fe520f477e555c9997683d762aff8bd1402ae6938dd5c994780b1bf6aa7239e9d8101630ecfeaa730d2bbc97d39beb057f016db2e28bf12fab4989c0170c2593383fd04660b5229adcd8486ba78f6cc1b558bcd92f344100dff239a8c00dbc4c2825277f24bdd04475bcc9a8c39fd895eff97c1967e434effcb9bd394e0577f4cf98c30d9e6b54cd47d6e447dcf34d67e48e4421691dbe4a7d9bd503abb9"

//
// The following routine exercises most of the core functions of
// the library. We've commented it as well as possible to give
// you the flavor of how libzerocoin works.
//
// For details on Zerocoin integration, see the libzerocoin wiki
// at: https://github.com/Zerocoin/libzerocoin/wiki
//

bool
ZerocoinTutorial()
{
	// The following simple code illustrates the call flow for Zerocoin
	// applications. In a real currency network these operations would
	// be split between individual payers/payees, network nodes and miners.
	//
	// For each call we specify the participant who would use it.

	// Zerocoin uses exceptions (based on the runtime_error class)
	// to indicate all sorts of problems. Always remember to catch them!

	try {

		/********************************************************************/
		// What is it:      Parameter loading
		// Who does it:     ALL ZEROCOIN PARTICIPANTS
		// What it does:    Loads a trusted Zerocoin modulus "N" and
		//                  generates all associated parameters from it.
		//                  We use a hardcoded "N" that we generated using
		//                  the included 'paramgen' utility.
		/********************************************************************/

		// Load a test modulus from our hardcoded string (above)
		Bignum testModulus;
		testModulus.SetHex(std::string(TUTORIAL_TEST_MODULUS));

		// Set up the Zerocoin Params object
		libzerocoin::Params* params = new libzerocoin::Params(testModulus);

		cout << "Successfully loaded parameters." << endl;

		/********************************************************************/
		// What is it:      Coin generation
		// Who does it:     ZEROCOIN CLIENTS
		// What it does:    Generates a new 'zerocoin' coin using the
		//                  public parameters. Once generated, the client
		//                  will transmit the public portion of this coin
		//                  in a ZEROCOIN_MINT transaction. The inputs
		//                  to this transaction must add up to the zerocoin
		//                  denomination plus any transaction fees.
		/********************************************************************/

		// The following constructor does all the work of minting a brand
		// new zerocoin. It stores all the private values inside the
		// PrivateCoin object. This includes the coin secrets, which must be
		// stored in a secure location (wallet) at the client.
		libzerocoin::PrivateCoin newCoin(params);

		// Get a copy of the 'public' portion of the coin. You should
		// embed this into a Zerocoin 'MINT' transaction along with a series
		// of currency inputs totaling the assigned value of one zerocoin.
		libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin();

		cout << "Successfully minted a zerocoin." << endl;

		// Serialize the public coin to a CDataStream object.
		CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION);
		serializedCoin << pubCoin;

		/********************************************************************/
		// What is it:      Coin verification
		// Who does it:     TRANSACTION VERIFIERS
		// What it does:    Verifies the structure of a zerocoin obtained from
		//                  a ZEROCOIN_MINT transaction. All coins must be
		//                  verified before you operate on them.
		//                  Note that this is only part of the transaction
		//                  verification process! The client must also check
		//                  that (1) the inputs to the transaction are valid
		//                  and add up to the value of one zerocoin, (2) that
		//                  this particular zerocoin has not been minted before.
		/********************************************************************/

		// Deserialize the public coin into a fresh object. This will
		// automatically validate that the coin is correctly structured and
		// will throw an exception if it isn't. (You need to handle those.)
		libzerocoin::PublicCoin pubCoinNew(params, serializedCoin);

		cout << "Deserialized and verified the coin." << endl;

		/********************************************************************/
		// What is it:      Accumulator computation
		// Who does it:     ZEROCOIN CLIENTS & TRANSACTION VERIFIERS
		// What it does:    Collects a number of PublicCoin values drawn from
		//                  the block chain and calculates an accumulator.
		//                  This accumulator is incrementally computable;
		//                  you can stop and serialize it at any point
		//                  then continue accumulating new transactions.
		//                  The accumulator is also order-independent, so
		//                  the same coins can be accumulated in any order
		//                  to give the same result.
		//                  WARNING: do not accumulate the same coin twice!
		/********************************************************************/

		// Create an empty accumulator object
		libzerocoin::Accumulator accumulator(params);

		// Add several coins to it (we'll generate them here on the fly).
		for (uint32_t i = 0; i < COINS_TO_ACCUMULATE; i++) {
			libzerocoin::PrivateCoin testCoin(params);
			accumulator += testCoin.getPublicCoin();
		}

		// Serialize the accumulator object.
		//
		// If you're using Accumulator Checkpoints, each miner would
		// start by deserializing the accumulator checkpoint from the
		// previous block (or creating a new Accumulator if no previous
		// block exists). It will then add all the coins in the new block,
		// then serialize the resulting Accumulator object to obtain the
		// new checkpoint. All block verifiers should do the same thing
		// to check their work.
		CDataStream serializedAccumulator(SER_NETWORK, PROTOCOL_VERSION);
		serializedAccumulator << accumulator;

		// Deserialize the accumulator object
		libzerocoin::Accumulator newAccumulator(params, serializedAccumulator);

		// We can now continue accumulating things into the accumulator
		// we just deserialized. For example, let's put in the coin
		// we generated up above.
		newAccumulator += pubCoinNew;

		cout << "Successfully accumulated coins." << endl;

		/********************************************************************/
		// What is it:      Coin spend
		// Who does it:     ZEROCOIN CLIENTS
		// What it does:    Create a new transaction that spends a Zerocoin.
		//                  The user first authors a transaction specifying
		//                  a set of destination addresses (outputs). They
		//                  next compute an Accumulator over all coins in the
		//                  block chain (see above) and a Witness based on the
		//                  coin to be spent. Finally they instantiate a CoinSpend
		//                  object that 'signs' the transaction with a special
		//                  zero knowledge signature of knowledge over the coin
		//                  data, Witness and Accumulator.
		/********************************************************************/

		// We are going to spend the coin "newCoin" that we generated at the
		// top of this function.
		//
		// We'll use the accumulator we constructed above. This contains
		// a set of coins, but does NOT include the coin "newCoin".
		//
		// To generate the witness, we start with this accumulator and
		// add the public half of the coin we want to spend.
		libzerocoin::AccumulatorWitness witness(params, accumulator, newCoin.getPublicCoin());

		// Add the public half of "newCoin" to the Accumulator itself.
		accumulator += newCoin.getPublicCoin();

		// At this point we should generate a ZEROCOIN_SPEND transaction to
		// send to the network. This network should include a set of outputs
		// totalling to the value of one zerocoin (minus transaction fees).
		//
		// The format of this transaction is up to the implementer. Here we'll
		// assume you've formatted this transaction and placed the hash into
		// "transactionHash". We'll also assume "accumulatorHash" contains the
		// hash of the last block whose transactions are in the accumulator.
		uint256 transactionHash = DUMMY_TRANSACTION_HASH;
		uint256 accumulatorID = DUMMY_ACCUMULATOR_ID;

		// Place "transactionHash" and "accumulatorBlockHash" into a new
		// SpendMetaData object.
		libzerocoin::SpendMetaData metaData(accumulatorID, transactionHash);

		// Construct the CoinSpend object. This acts like a signature on the
		// transaction.
		libzerocoin::CoinSpend spend(params, newCoin, accumulator, witness, metaData);

		// Serialize the CoinSpend object into a buffer.
		CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION);
		serializedCoinSpend << spend;

		/********************************************************************/
		// What is it:      Coin spend verification
		// Who does it:     ALL PARTIES
		// What it does:    Verifies that a CoinSpend signature is correct
		//                  with respect to a ZEROCOIN_SPEND transaction hash.
		//                  The client must also extract the serial number from
		//                  the CoinSpend and verify that this serial number has
		//                  not previously appeared in another ZEROCOIN_SPEND
		//                  transaction.
		/********************************************************************/

		// Deserialize the CoinSpend intro a fresh object
		libzerocoin::CoinSpend newSpend(params, serializedCoinSpend);

		// Verify that the spend is valid with respect
		if (newSpend.Verify(accumulator)

		        cout << "Successfully generated a coin spend transaction." << endl;

		        // We're done
		        return true;

	} catch (runtime_error &e) {
		cout << e.what() << endl;
		return false;
	}

	return false;
}

int main(int argc, char **argv)
{
	cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " tutorial." << endl << endl;

	ZerocoinTutorial();
}
<commit_msg>Finished the Tutorial program. This still needs a Makefile entry.<commit_after>/**
* @file       tutorial.cpp
*
* @brief      Simple tutorial program to illustrate Zerocoin usage.
*
* @author     Ian Miers, Christina Garman and Matthew Green
* @date       June 2013
*
* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
* @license    This project is released under the MIT license.
**/

using namespace std;

#include <string>
#include <iostream>
#include <fstream>
#include <curses.h>
#include <exception>
#include "Zerocoin.h"

#define COINS_TO_ACCUMULATE     5
#define DUMMY_TRANSACTION_HASH  0 // in real life these would be uint256 hashes
#define DUMMY_ACCUMULATOR_ID    0 // in real life these would be uint256 hashes

//
// We generated this for testing only. Don't use it in production!
//
#define TUTORIAL_TEST_MODULUS   "a8852ebf7c49f01cd196e35394f3b74dd86283a07f57e0a262928e7493d4a3961d93d93c90ea3369719641d626d28b9cddc6d9307b9aabdbffc40b6d6da2e329d079b4187ff784b2893d9f53e9ab913a04ff02668114695b07d8ce877c4c8cac1b12b9beff3c51294ebe349eca41c24cd32a6d09dd1579d3947e5c4dcc30b2090b0454edb98c6336e7571db09e0fdafbd68d8f0470223836e90666a5b143b73b9cd71547c917bf24c0efc86af2eba046ed781d9acb05c80f007ef5a0a5dfca23236f37e698e8728def12554bc80f294f71c040a88eff144d130b24211016a97ce0f5fe520f477e555c9997683d762aff8bd1402ae6938dd5c994780b1bf6aa7239e9d8101630ecfeaa730d2bbc97d39beb057f016db2e28bf12fab4989c0170c2593383fd04660b5229adcd8486ba78f6cc1b558bcd92f344100dff239a8c00dbc4c2825277f24bdd04475bcc9a8c39fd895eff97c1967e434effcb9bd394e0577f4cf98c30d9e6b54cd47d6e447dcf34d67e48e4421691dbe4a7d9bd503abb9"

//
// The following routine exercises most of the core functions of
// the library. We've commented it as well as possible to give
// you the flavor of how libzerocoin works.
//
// For details on Zerocoin integration, see the libzerocoin wiki
// at: https://github.com/Zerocoin/libzerocoin/wiki
//

bool
ZerocoinTutorial()
{
	// The following simple code illustrates the call flow for Zerocoin
	// applications. In a real currency network these operations would
	// be split between individual payers/payees, network nodes and miners.
	//
	// For each call we specify the participant who would use it.

	// Zerocoin uses exceptions (based on the runtime_error class)
	// to indicate all sorts of problems. Always remember to catch them!

	try {

		/********************************************************************/
		// What is it:      Parameter loading
		// Who does it:     ALL ZEROCOIN PARTICIPANTS
		// What it does:    Loads a trusted Zerocoin modulus "N" and
		//                  generates all associated parameters from it.
		//                  We use a hardcoded "N" that we generated using
		//                  the included 'paramgen' utility.
		/********************************************************************/

		// Load a test modulus from our hardcoded string (above)
		Bignum testModulus;
		testModulus.SetHex(std::string(TUTORIAL_TEST_MODULUS));

		// Set up the Zerocoin Params object
		libzerocoin::Params* params = new libzerocoin::Params(testModulus);

		cout << "Successfully loaded parameters." << endl;

		/********************************************************************/
		// What is it:      Coin generation
		// Who does it:     ZEROCOIN CLIENTS
		// What it does:    Generates a new 'zerocoin' coin using the
		//                  public parameters. Once generated, the client
		//                  will transmit the public portion of this coin
		//                  in a ZEROCOIN_MINT transaction. The inputs
		//                  to this transaction must add up to the zerocoin
		//                  denomination plus any transaction fees.
		/********************************************************************/

		// The following constructor does all the work of minting a brand
		// new zerocoin. It stores all the private values inside the
		// PrivateCoin object. This includes the coin secrets, which must be
		// stored in a secure location (wallet) at the client.
		libzerocoin::PrivateCoin newCoin(params);

		// Get a copy of the 'public' portion of the coin. You should
		// embed this into a Zerocoin 'MINT' transaction along with a series
		// of currency inputs totaling the assigned value of one zerocoin.
		libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin();

		cout << "Successfully minted a zerocoin." << endl;

		// Serialize the public coin to a CDataStream object.
		CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION);
		serializedCoin << pubCoin;

		/********************************************************************/
		// What is it:      Coin verification
		// Who does it:     TRANSACTION VERIFIERS
		// What it does:    Verifies the structure of a zerocoin obtained from
		//                  a ZEROCOIN_MINT transaction. All coins must be
		//                  verified before you operate on them.
		//                  Note that this is only part of the transaction
		//                  verification process! The client must also check
		//                  that (1) the inputs to the transaction are valid
		//                  and add up to the value of one zerocoin, (2) that
		//                  this particular zerocoin has not been minted before.
		/********************************************************************/

		// Deserialize the public coin into a fresh object. This will
		// automatically validate that the coin is correctly structured and
		// will throw an exception if it isn't. (You need to handle those.)
		libzerocoin::PublicCoin pubCoinNew(params, serializedCoin);

		cout << "Deserialized and verified the coin." << endl;

		/********************************************************************/
		// What is it:      Accumulator computation
		// Who does it:     ZEROCOIN CLIENTS & TRANSACTION VERIFIERS
		// What it does:    Collects a number of PublicCoin values drawn from
		//                  the block chain and calculates an accumulator.
		//                  This accumulator is incrementally computable;
		//                  you can stop and serialize it at any point
		//                  then continue accumulating new transactions.
		//                  The accumulator is also order-independent, so
		//                  the same coins can be accumulated in any order
		//                  to give the same result.
		//                  WARNING: do not accumulate the same coin twice!
		/********************************************************************/

		// Create an empty accumulator object
		libzerocoin::Accumulator accumulator(params);

		// Add several coins to it (we'll generate them here on the fly).
		for (uint32_t i = 0; i < COINS_TO_ACCUMULATE; i++) {
			libzerocoin::PrivateCoin testCoin(params);
			accumulator += testCoin.getPublicCoin();
		}

		// Serialize the accumulator object.
		//
		// If you're using Accumulator Checkpoints, each miner would
		// start by deserializing the accumulator checkpoint from the
		// previous block (or creating a new Accumulator if no previous
		// block exists). It will then add all the coins in the new block,
		// then serialize the resulting Accumulator object to obtain the
		// new checkpoint. All block verifiers should do the same thing
		// to check their work.
		CDataStream serializedAccumulator(SER_NETWORK, PROTOCOL_VERSION);
		serializedAccumulator << accumulator;

		// Deserialize the accumulator object
		libzerocoin::Accumulator newAccumulator(params, serializedAccumulator);

		// We can now continue accumulating things into the accumulator
		// we just deserialized. For example, let's put in the coin
		// we generated up above.
		newAccumulator += pubCoinNew;

		cout << "Successfully accumulated coins." << endl;

		/********************************************************************/
		// What is it:      Coin spend
		// Who does it:     ZEROCOIN CLIENTS
		// What it does:    Create a new transaction that spends a Zerocoin.
		//                  The user first authors a transaction specifying
		//                  a set of destination addresses (outputs). They
		//                  next compute an Accumulator over all coins in the
		//                  block chain (see above) and a Witness based on the
		//                  coin to be spent. Finally they instantiate a CoinSpend
		//                  object that 'signs' the transaction with a special
		//                  zero knowledge signature of knowledge over the coin
		//                  data, Witness and Accumulator.
		/********************************************************************/

		// We are going to spend the coin "newCoin" that we generated at the
		// top of this function.
		//
		// We'll use the accumulator we constructed above. This contains
		// a set of coins, but does NOT include the coin "newCoin".
		//
		// To generate the witness, we start with this accumulator and
		// add the public half of the coin we want to spend.
		libzerocoin::AccumulatorWitness witness(params, accumulator, newCoin.getPublicCoin());

		// Add the public half of "newCoin" to the Accumulator itself.
		accumulator += newCoin.getPublicCoin();

		// At this point we should generate a ZEROCOIN_SPEND transaction to
		// send to the network. This network should include a set of outputs
		// totalling to the value of one zerocoin (minus transaction fees).
		//
		// The format of this transaction is up to the implementer. Here we'll
		// assume you've formatted this transaction and placed the hash into
		// "transactionHash". We'll also assume "accumulatorHash" contains the
		// hash of the last block whose transactions are in the accumulator.
		uint256 transactionHash = DUMMY_TRANSACTION_HASH;
		uint256 accumulatorID = DUMMY_ACCUMULATOR_ID;

		// Place "transactionHash" and "accumulatorBlockHash" into a new
		// SpendMetaData object.
		libzerocoin::SpendMetaData metaData(accumulatorID, transactionHash);

		// Construct the CoinSpend object. This acts like a signature on the
		// transaction.
		libzerocoin::CoinSpend spend(params, newCoin, accumulator, witness, metaData);

		// Serialize the CoinSpend object into a buffer.
		CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION);
		serializedCoinSpend << spend;

		cout << "Successfully generated a coin spend transaction." << endl;

		/********************************************************************/
		// What is it:      Coin spend verification
		// Who does it:     ALL PARTIES
		// What it does:    Verifies that a CoinSpend signature is correct
		//                  with respect to a ZEROCOIN_SPEND transaction hash.
		//                  The client must also extract the serial number from
		//                  the CoinSpend and verify that this serial number has
		//                  not previously appeared in another ZEROCOIN_SPEND
		//                  transaction.
		/********************************************************************/

		// Deserialize the CoinSpend intro a fresh object
		libzerocoin::CoinSpend newSpend(params, serializedCoinSpend);

		// Create a new metadata object to contain the hash of the received
		// ZEROCOIN_SPEND transactiond ata
		// Place "transactionHash" and "accumulatorBlockHash" into a new
		// SpendMetaData object.
		libzerocoin::SpendMetaData newMetadata(accumulatorID, transactionHash);

		// Verify that the spend is valid with respect to the Accumulator
		// and the Metadata
		if (!newSpend.Verify(accumulator, newMetadata)) {
			cout << "ERROR: The CoinSpend transaction did not verify!" << endl;
			return false;
		}

		// Pull the serial number out of the CoinSpend object. If we
		// were a real Zerocoin client we would now check that the serial number
		// has not been spent before (in another ZEROCOIN_SPEND) transaction.
		// The serial number is stored as a Bignum.
		Bignum serialNumber = 	newSpend.getCoinSerialNumber();

		cout << "Successfully verified a coin spend transaction." << endl;
		cout << endl << "Coin serial number is:" << endl << serialNumber << endl;

		// We're done
		return true;

	} catch (runtime_error &e) {
		cout << e.what() << endl;
		return false;
	}

	return false;
}

int main(int argc, char **argv)
{
	cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " tutorial." << endl << endl;

	ZerocoinTutorial();
}
<|endoftext|>


<commit_before>#ifndef slic3r_BoundingBox_hpp_
#define slic3r_BoundingBox_hpp_

#include "libslic3r.h"
#include "Point.hpp"
#include "Polygon.hpp"

namespace Slic3r {

typedef Point   Size;
typedef Point3  Size3;
typedef Pointf  Sizef;
typedef Pointf3 Sizef3;

template <class PointClass>
class BoundingBoxBase
{
    public:
    PointClass min;
    PointClass max;
    bool defined;

    BoundingBoxBase() : defined(false) {};
    BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) :
        min(pmin), max(pmax), defined(pmin.x < pmax.x && pmin.y < pmax.y) {}
    BoundingBoxBase(const std::vector<PointClass> &points);
    void merge(const PointClass &point);
    void merge(const std::vector<PointClass> &points);
    void merge(const BoundingBoxBase<PointClass> &bb);
    void scale(double factor);
    PointClass size() const;
    double radius() const;
    void translate(coordf_t x, coordf_t y) { this->min.translate(x, y); this->max.translate(x, y); }
    void translate(const Pointf &pos) { this->translate(pos.x, pos.y); }
    void offset(coordf_t delta);
    PointClass center() const;
    bool contains(const PointClass &point) const {
        return point.x >= this->min.x && point.x <= this->max.x
            && point.y >= this->min.y && point.y <= this->max.y;
    }
    bool overlap(const BoundingBoxBase<PointClass> &other) const {
        return ! (this->max.x < other.min.x || this->min.x > other.max.x ||
                  this->max.y < other.min.y || this->min.y > other.max.y);
    }
};

template <class PointClass>
class BoundingBox3Base : public BoundingBoxBase<PointClass>
{
    public:
    BoundingBox3Base() : BoundingBoxBase<PointClass>() {};
    BoundingBox3Base(const PointClass &pmin, const PointClass &pmax) :
        BoundingBoxBase<PointClass>(pmin, pmax)
        { if (pmin.z >= pmax.z) BoundingBoxBase<PointClass>::defined = false; }
    BoundingBox3Base(const std::vector<PointClass> &points);
    void merge(const PointClass &point);
    void merge(const std::vector<PointClass> &points);
    void merge(const BoundingBox3Base<PointClass> &bb);
    PointClass size() const;
    double radius() const;
    void translate(coordf_t x, coordf_t y, coordf_t z) { this->min.translate(x, y, z); this->max.translate(x, y, z); }
    void translate(const Pointf3 &pos) { this->translate(pos.x, pos.y, pos.z); }
    void offset(coordf_t delta);
    PointClass center() const;
};

class BoundingBox : public BoundingBoxBase<Point>
{
    public:
    void polygon(Polygon* polygon) const;
    Polygon polygon() const;
    BoundingBox rotated(double angle) const;
    BoundingBox rotated(double angle, const Point &center) const;
    void rotate(double angle) { (*this) = this->rotated(angle); }
    void rotate(double angle, const Point &center) { (*this) = this->rotated(angle, center); }
    // Align the min corner to a grid of cell_size x cell_size cells,
    // to encompass the original bounding box.
    void align_to_grid(const coord_t cell_size);

    BoundingBox() : BoundingBoxBase<Point>() {};
    BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point>(pmin, pmax) {};
    BoundingBox(const Points &points) : BoundingBoxBase<Point>(points) {};
    BoundingBox(const Lines &lines);

    friend BoundingBox get_extents_rotated(const Points &points, double angle);
};

/*
class BoundingBox3  : public BoundingBox3Base<Point3> {};
*/

class BoundingBoxf : public BoundingBoxBase<Pointf> {
    public:
    BoundingBoxf() : BoundingBoxBase<Pointf>() {};
    BoundingBoxf(const Pointf &pmin, const Pointf &pmax) : BoundingBoxBase<Pointf>(pmin, pmax) {};
    BoundingBoxf(const std::vector<Pointf> &points) : BoundingBoxBase<Pointf>(points) {};
};

class BoundingBoxf3 : public BoundingBox3Base<Pointf3> {
    public:
    BoundingBoxf3() : BoundingBox3Base<Pointf3>() {};
    BoundingBoxf3(const Pointf3 &pmin, const Pointf3 &pmax) : BoundingBox3Base<Pointf3>(pmin, pmax) {};
    BoundingBoxf3(const std::vector<Pointf3> &points) : BoundingBox3Base<Pointf3>(points) {};
};

template<typename VT>
inline bool operator==(const BoundingBoxBase<VT> &bb1, const BoundingBoxBase<VT> &bb2)
{
    return bb1.min == bb2.min && bb1.max == bb2.max;
}

template<typename VT>
inline bool operator!=(const BoundingBoxBase<VT> &bb1, const BoundingBoxBase<VT> &bb2)
{
    return !(bb1 == bb2);
}

template<typename VT>
inline bool empty(const BoundingBoxBase<VT> &bb)
{
    return ! bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y;
}

template<typename VT>
inline bool empty(const BoundingBox3Base<VT> &bb)
{
    return ! bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y || bb.min.z >= bb.max.z;
}

} // namespace Slic3r

#endif
<commit_msg>New BoundingBox3 class.<commit_after>#ifndef slic3r_BoundingBox_hpp_
#define slic3r_BoundingBox_hpp_

#include "libslic3r.h"
#include "Point.hpp"
#include "Polygon.hpp"

namespace Slic3r {

typedef Point   Size;
typedef Point3  Size3;
typedef Pointf  Sizef;
typedef Pointf3 Sizef3;

template <class PointClass>
class BoundingBoxBase
{
    public:
    PointClass min;
    PointClass max;
    bool defined;

    BoundingBoxBase() : defined(false) {};
    BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) :
        min(pmin), max(pmax), defined(pmin.x < pmax.x && pmin.y < pmax.y) {}
    BoundingBoxBase(const std::vector<PointClass> &points);
    void merge(const PointClass &point);
    void merge(const std::vector<PointClass> &points);
    void merge(const BoundingBoxBase<PointClass> &bb);
    void scale(double factor);
    PointClass size() const;
    double radius() const;
    void translate(coordf_t x, coordf_t y) { this->min.translate(x, y); this->max.translate(x, y); }
    void translate(const Pointf &pos) { this->translate(pos.x, pos.y); }
    void offset(coordf_t delta);
    PointClass center() const;
    bool contains(const PointClass &point) const {
        return point.x >= this->min.x && point.x <= this->max.x
            && point.y >= this->min.y && point.y <= this->max.y;
    }
    bool overlap(const BoundingBoxBase<PointClass> &other) const {
        return ! (this->max.x < other.min.x || this->min.x > other.max.x ||
                  this->max.y < other.min.y || this->min.y > other.max.y);
    }
};

template <class PointClass>
class BoundingBox3Base : public BoundingBoxBase<PointClass>
{
    public:
    BoundingBox3Base() : BoundingBoxBase<PointClass>() {};
    BoundingBox3Base(const PointClass &pmin, const PointClass &pmax) :
        BoundingBoxBase<PointClass>(pmin, pmax)
        { if (pmin.z >= pmax.z) BoundingBoxBase<PointClass>::defined = false; }
    BoundingBox3Base(const std::vector<PointClass> &points);
    void merge(const PointClass &point);
    void merge(const std::vector<PointClass> &points);
    void merge(const BoundingBox3Base<PointClass> &bb);
    PointClass size() const;
    double radius() const;
    void translate(coordf_t x, coordf_t y, coordf_t z) { this->min.translate(x, y, z); this->max.translate(x, y, z); }
    void translate(const Pointf3 &pos) { this->translate(pos.x, pos.y, pos.z); }
    void offset(coordf_t delta);
    PointClass center() const;
};

class BoundingBox : public BoundingBoxBase<Point>
{
    public:
    void polygon(Polygon* polygon) const;
    Polygon polygon() const;
    BoundingBox rotated(double angle) const;
    BoundingBox rotated(double angle, const Point &center) const;
    void rotate(double angle) { (*this) = this->rotated(angle); }
    void rotate(double angle, const Point &center) { (*this) = this->rotated(angle, center); }
    // Align the min corner to a grid of cell_size x cell_size cells,
    // to encompass the original bounding box.
    void align_to_grid(const coord_t cell_size);

    BoundingBox() : BoundingBoxBase<Point>() {};
    BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point>(pmin, pmax) {};
    BoundingBox(const Points &points) : BoundingBoxBase<Point>(points) {};
    BoundingBox(const Lines &lines);

    friend BoundingBox get_extents_rotated(const Points &points, double angle);
};

class BoundingBox3  : public BoundingBox3Base<Point3>
{
    BoundingBox3() : BoundingBox3Base<Point3>() {};
    BoundingBox3(const Point3 &pmin, const Point3 &pmax) : BoundingBox3Base<Point3>(pmin, pmax) {};
    BoundingBox3(const std::vector<Point3> &points) : BoundingBox3Base<Point3>(points) {};
};

class BoundingBoxf : public BoundingBoxBase<Pointf>
{
public:
    BoundingBoxf() : BoundingBoxBase<Pointf>() {};
    BoundingBoxf(const Pointf &pmin, const Pointf &pmax) : BoundingBoxBase<Pointf>(pmin, pmax) {};
    BoundingBoxf(const std::vector<Pointf> &points) : BoundingBoxBase<Pointf>(points) {};
};

class BoundingBoxf3 : public BoundingBox3Base<Pointf3>
{
public:
    BoundingBoxf3() : BoundingBox3Base<Pointf3>() {};
    BoundingBoxf3(const Pointf3 &pmin, const Pointf3 &pmax) : BoundingBox3Base<Pointf3>(pmin, pmax) {};
    BoundingBoxf3(const std::vector<Pointf3> &points) : BoundingBox3Base<Pointf3>(points) {};
};

template<typename VT>
inline bool operator==(const BoundingBoxBase<VT> &bb1, const BoundingBoxBase<VT> &bb2)
{
    return bb1.min == bb2.min && bb1.max == bb2.max;
}

template<typename VT>
inline bool operator!=(const BoundingBoxBase<VT> &bb1, const BoundingBoxBase<VT> &bb2)
{
    return !(bb1 == bb2);
}

template<typename VT>
inline bool empty(const BoundingBoxBase<VT> &bb)
{
    return ! bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y;
}

template<typename VT>
inline bool empty(const BoundingBox3Base<VT> &bb)
{
    return ! bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y || bb.min.z >= bb.max.z;
}

} // namespace Slic3r

#endif
<|endoftext|>


<commit_before>#include "Layer.hpp"
#include "BridgeDetector.hpp"
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include "PerimeterGenerator.hpp"
#include "Print.hpp"
#include "Surface.hpp"

namespace Slic3r {

/// Creates a new Flow object with the arguments and the variables of this LayerRegion
Flow
LayerRegion::flow(FlowRole role, bool bridge, double width) const
{
    return this->_region->flow(
        role,
        this->_layer->height,
        bridge,
        this->_layer->id() == 0,
        width,
        *this->_layer->object()
    );
}

/// Merges this->slices with union_ex, and then repopulates this->slices.surfaces
void
LayerRegion::merge_slices()
{
    // without safety offset, artifacts are generated (GH #2494)
    ExPolygons expp = union_ex((Polygons)this->slices, true);
    this->slices.surfaces.clear();
    this->slices.surfaces.reserve(expp.size());

    for (ExPolygons::const_iterator expoly = expp.begin(); expoly != expp.end(); ++expoly)
        this->slices.surfaces.push_back(Surface(stInternal, *expoly));
}

/// Creates a new PerimeterGenerator object
/// Which will return the perimeters by its construction
void
LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
{
    this->perimeters.clear();
    this->thin_fills.clear();

    PerimeterGenerator g(
        // input:
        &slices,
        this->layer()->height,
        this->flow(frPerimeter),
        &this->region()->config,
        &this->layer()->object()->config,
        &this->layer()->object()->print()->config,

        // output:
        &this->perimeters,
        &this->thin_fills,
        fill_surfaces
    );

    if (this->layer()->lower_layer != NULL)
        // Cummulative sum of polygons over all the regions.
        g.lower_slices = &this->layer()->lower_layer->slices;

    g.layer_id              = this->layer()->id();
    g.ext_perimeter_flow    = this->flow(frExternalPerimeter);
    g.overhang_flow         = this->region()->flow(frPerimeter, -1, true, false, -1, *this->layer()->object());
    g.solid_infill_flow     = this->flow(frSolidInfill);

    g.process();
}

/// Processes bridges with holes which are internal features.
/// Detects same-orientation bridges and merges them.
/// Processes and groups top and bottom surfaces
/// This function reads layer->slices and lower_layer->slices
/// and writes this->bridged and this->fill_surfaces, so it's thread-safe.
void
LayerRegion::process_external_surfaces()
{
    Surfaces &surfaces = this->fill_surfaces.surfaces;

    for (size_t j = 0; j < surfaces.size(); ++j) {
        // we don't get any reference to surface because it would be invalidated
        // by the erase() call below

        if (this->layer()->lower_layer != NULL && surfaces[j].is_bridge()) {
            // If this bridge has one or more holes that are internal surfaces
            // (thus not visible from the outside), like a slab sustained by
            // pillars, include them in the bridge in order to have better and
            // more continuous bridging.
            for (size_t i = 0; i < surfaces[j].expolygon.holes.size(); ++i) {
                // reverse the hole and consider it a polygon
                Polygon h = surfaces[j].expolygon.holes[i];
                h.reverse();

                // Is this hole fully contained in the layer slices?
                if (diff(h, this->layer()->slices).empty()) {
                    // remove any other surface contained in this hole
                    for (size_t k = 0; k < surfaces.size(); ++k) {
                        if (k == j) continue;
                        if (h.contains(surfaces[k].expolygon.contour.first_point())) {
                            surfaces.erase(surfaces.begin() + k);
                            if (j > k) --j;
                            --k;
                        }
                    }

                    Polygons &holes = surfaces[j].expolygon.holes;
                    holes.erase(holes.begin() + i);
                    --i;
                }
            }
        }
    }

    SurfaceCollection bottom;
    for (const Surface &surface : surfaces) {
        if (!surface.is_bottom()) continue;

        /*  detect bridge direction before merging grown surfaces otherwise adjacent bridges
            would get merged into a single one while they need different directions
            also, supply the original expolygon instead of the grown one, because in case
            of very thin (but still working) anchors, the grown expolygon would go beyond them */
        double angle = -1;
        if (this->layer()->lower_layer != NULL && surface.is_bridge()) {
            BridgeDetector bd(
                surface.expolygon,
                this->layer()->lower_layer->slices,
                this->flow(frInfill, true).scaled_width()
            );

            #ifdef SLIC3R_DEBUG
            printf("Processing bridge at layer %zu (z = %f):\n", this->layer()->id(), this->layer()->print_z);
            #endif

            if (bd.detect_angle()) {
                angle = bd.angle;

                if (this->layer()->object()->config.support_material) {
                    append_to(this->bridged, bd.coverage());
                    this->unsupported_bridge_edges.append(bd.unsupported_edges());
                }
            }
        }

        const ExPolygons grown = offset_ex(surface.expolygon, +SCALED_EXTERNAL_INFILL_MARGIN);
        Surface templ = surface;
        templ.bridge_angle = angle;
        bottom.append(grown, templ);
    }

    SurfaceCollection top;
    for (const Surface &surface : surfaces) {
        if (!surface.is_top()) continue;

        // give priority to bottom surfaces
        ExPolygons grown = diff_ex(
            offset(surface.expolygon, +SCALED_EXTERNAL_INFILL_MARGIN),
            (Polygons)bottom
        );
        top.append(grown, surface);
    }

    /*  if we're slicing with no infill, we can't extend external surfaces
        over non-existent infill */
    SurfaceCollection fill_boundaries;
    if (this->region()->config.fill_density.value > 0) {
        fill_boundaries = SurfaceCollection(surfaces);
    } else {
        for (const Surface &s : surfaces)
            if (s.surface_type != stInternal)
                fill_boundaries.surfaces.push_back(s);
    }

    // intersect the grown surfaces with the actual fill boundaries
    SurfaceCollection new_surfaces;
    {
        // merge top and bottom in a single collection
        SurfaceCollection tb = top;
        tb.append(bottom);

        // group surfaces
        std::vector<SurfacesConstPtr> groups;
        tb.group(&groups);

        for (const SurfacesConstPtr &g : groups) {
            Polygons subject;
            for (const Surface* s : g)
                append_to(subject, (Polygons)*s);

            ExPolygons expp = intersection_ex(
                subject,
                (Polygons)fill_boundaries,
                true // to ensure adjacent expolygons are unified
            );

            new_surfaces.append(expp, *g.front());
        }
    }

    /* subtract the new top surfaces from the other non-top surfaces and re-add them */
    {
        SurfaceCollection other;
        for (const Surface &s : surfaces)
            if (!s.is_top() && !s.is_bottom())
                other.surfaces.push_back(s);

        // group surfaces
        std::vector<SurfacesConstPtr> groups;
        other.group(&groups);

        for (const SurfacesConstPtr &g : groups) {
            Polygons subject;
            for (const Surface* s : g)
                append_to(subject, (Polygons)*s);

            ExPolygons expp = diff_ex(
                subject,
                (Polygons)new_surfaces
            );

            new_surfaces.append(expp, *g.front());
        }
    }

    this->fill_surfaces = std::move(new_surfaces);
}

/// If no solid layers are requested, turns top/bottom surfaces to internal
/// Turns too small internal regions into solid regions according to the user setting
void
LayerRegion::prepare_fill_surfaces()
{
    /*  Note: in order to make the psPrepareInfill step idempotent, we should never
        alter fill_surfaces boundaries on which our idempotency relies since that's
        the only meaningful information returned by psPerimeters. */

    // if no solid layers are requested, turn top/bottom surfaces to internal
    if (this->region()->config.top_solid_layers == 0 && this->region()->config.min_top_bottom_shell_thickness <= 0) {
        for (Surface &surface : this->fill_surfaces.surfaces) {
            if (surface->surface_type == stTop) {
                if (this->layer()->object()->config.infill_only_where_needed) {
                    surface->surface_type = (stInternal | stVoid);
                } else {
                    surface->surface_type = stInternal;
                }
            }
        }
    }

    if (this->region()->config.bottom_solid_layers == 0 && this->region()->config.min_top_bottom_shell_thickness <= 0) {
        for (Surface &surface : this->fill_surfaces.surfaces) {
            if (surface->is_bottom())
                surface->surface_type = stInternal;
        }
    }

    // turn too small internal regions into solid regions according to the user setting
    const float &fill_density = this->region()->config.fill_density;
    if (fill_density > 0 && fill_density < 100) {
        // scaling an area requires two calls!
        // (we don't use scale_() because it would overflow the coord_t range
        const double min_area = this->region()->config.solid_infill_below_area.value / SCALING_FACTOR / SCALING_FACTOR;
        for (Surface &surface : this->fill_surfaces.surfaces) {
            if (!surface.is_internal() && surface.area() <= min_area)
                surface.surface_type = (stInternal | stSolid);
        }
    }
}

///  Gets smallest area by squaring the Flow's scaled spacing
double
LayerRegion::infill_area_threshold() const
{
    double ss = this->flow(frSolidInfill).scaled_spacing();
    return ss*ss;
}

}
<commit_msg>stupid bugfix<commit_after>#include "Layer.hpp"
#include "BridgeDetector.hpp"
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include "PerimeterGenerator.hpp"
#include "Print.hpp"
#include "Surface.hpp"

namespace Slic3r {

/// Creates a new Flow object with the arguments and the variables of this LayerRegion
Flow
LayerRegion::flow(FlowRole role, bool bridge, double width) const
{
    return this->_region->flow(
        role,
        this->_layer->height,
        bridge,
        this->_layer->id() == 0,
        width,
        *this->_layer->object()
    );
}

/// Merges this->slices with union_ex, and then repopulates this->slices.surfaces
void
LayerRegion::merge_slices()
{
    // without safety offset, artifacts are generated (GH #2494)
    ExPolygons expp = union_ex((Polygons)this->slices, true);
    this->slices.surfaces.clear();
    this->slices.surfaces.reserve(expp.size());

    for (ExPolygons::const_iterator expoly = expp.begin(); expoly != expp.end(); ++expoly)
        this->slices.surfaces.push_back(Surface(stInternal, *expoly));
}

/// Creates a new PerimeterGenerator object
/// Which will return the perimeters by its construction
void
LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
{
    this->perimeters.clear();
    this->thin_fills.clear();

    PerimeterGenerator g(
        // input:
        &slices,
        this->layer()->height,
        this->flow(frPerimeter),
        &this->region()->config,
        &this->layer()->object()->config,
        &this->layer()->object()->print()->config,

        // output:
        &this->perimeters,
        &this->thin_fills,
        fill_surfaces
    );

    if (this->layer()->lower_layer != NULL)
        // Cummulative sum of polygons over all the regions.
        g.lower_slices = &this->layer()->lower_layer->slices;

    g.layer_id              = this->layer()->id();
    g.ext_perimeter_flow    = this->flow(frExternalPerimeter);
    g.overhang_flow         = this->region()->flow(frPerimeter, -1, true, false, -1, *this->layer()->object());
    g.solid_infill_flow     = this->flow(frSolidInfill);

    g.process();
}

/// Processes bridges with holes which are internal features.
/// Detects same-orientation bridges and merges them.
/// Processes and groups top and bottom surfaces
/// This function reads layer->slices and lower_layer->slices
/// and writes this->bridged and this->fill_surfaces, so it's thread-safe.
void
LayerRegion::process_external_surfaces()
{
    Surfaces &surfaces = this->fill_surfaces.surfaces;

    for (size_t j = 0; j < surfaces.size(); ++j) {
        // we don't get any reference to surface because it would be invalidated
        // by the erase() call below

        if (this->layer()->lower_layer != NULL && surfaces[j].is_bridge()) {
            // If this bridge has one or more holes that are internal surfaces
            // (thus not visible from the outside), like a slab sustained by
            // pillars, include them in the bridge in order to have better and
            // more continuous bridging.
            for (size_t i = 0; i < surfaces[j].expolygon.holes.size(); ++i) {
                // reverse the hole and consider it a polygon
                Polygon h = surfaces[j].expolygon.holes[i];
                h.reverse();

                // Is this hole fully contained in the layer slices?
                if (diff(h, this->layer()->slices).empty()) {
                    // remove any other surface contained in this hole
                    for (size_t k = 0; k < surfaces.size(); ++k) {
                        if (k == j) continue;
                        if (h.contains(surfaces[k].expolygon.contour.first_point())) {
                            surfaces.erase(surfaces.begin() + k);
                            if (j > k) --j;
                            --k;
                        }
                    }

                    Polygons &holes = surfaces[j].expolygon.holes;
                    holes.erase(holes.begin() + i);
                    --i;
                }
            }
        }
    }

    SurfaceCollection bottom;
    for (const Surface &surface : surfaces) {
        if (!surface.is_bottom()) continue;

        /*  detect bridge direction before merging grown surfaces otherwise adjacent bridges
            would get merged into a single one while they need different directions
            also, supply the original expolygon instead of the grown one, because in case
            of very thin (but still working) anchors, the grown expolygon would go beyond them */
        double angle = -1;
        if (this->layer()->lower_layer != NULL && surface.is_bridge()) {
            BridgeDetector bd(
                surface.expolygon,
                this->layer()->lower_layer->slices,
                this->flow(frInfill, true).scaled_width()
            );

            #ifdef SLIC3R_DEBUG
            printf("Processing bridge at layer %zu (z = %f):\n", this->layer()->id(), this->layer()->print_z);
            #endif

            if (bd.detect_angle()) {
                angle = bd.angle;

                if (this->layer()->object()->config.support_material) {
                    append_to(this->bridged, bd.coverage());
                    this->unsupported_bridge_edges.append(bd.unsupported_edges());
                }
            }
        }

        const ExPolygons grown = offset_ex(surface.expolygon, +SCALED_EXTERNAL_INFILL_MARGIN);
        Surface templ = surface;
        templ.bridge_angle = angle;
        bottom.append(grown, templ);
    }

    SurfaceCollection top;
    for (const Surface &surface : surfaces) {
        if (!surface.is_top()) continue;

        // give priority to bottom surfaces
        ExPolygons grown = diff_ex(
            offset(surface.expolygon, +SCALED_EXTERNAL_INFILL_MARGIN),
            (Polygons)bottom
        );
        top.append(grown, surface);
    }

    /*  if we're slicing with no infill, we can't extend external surfaces
        over non-existent infill */
    SurfaceCollection fill_boundaries;
    if (this->region()->config.fill_density.value > 0) {
        fill_boundaries = SurfaceCollection(surfaces);
    } else {
        for (const Surface &s : surfaces)
            if (s.surface_type != stInternal)
                fill_boundaries.surfaces.push_back(s);
    }

    // intersect the grown surfaces with the actual fill boundaries
    SurfaceCollection new_surfaces;
    {
        // merge top and bottom in a single collection
        SurfaceCollection tb = top;
        tb.append(bottom);

        // group surfaces
        std::vector<SurfacesConstPtr> groups;
        tb.group(&groups);

        for (const SurfacesConstPtr &g : groups) {
            Polygons subject;
            for (const Surface* s : g)
                append_to(subject, (Polygons)*s);

            ExPolygons expp = intersection_ex(
                subject,
                (Polygons)fill_boundaries,
                true // to ensure adjacent expolygons are unified
            );

            new_surfaces.append(expp, *g.front());
        }
    }

    /* subtract the new top surfaces from the other non-top surfaces and re-add them */
    {
        SurfaceCollection other;
        for (const Surface &s : surfaces)
            if (!s.is_top() && !s.is_bottom())
                other.surfaces.push_back(s);

        // group surfaces
        std::vector<SurfacesConstPtr> groups;
        other.group(&groups);

        for (const SurfacesConstPtr &g : groups) {
            Polygons subject;
            for (const Surface* s : g)
                append_to(subject, (Polygons)*s);

            ExPolygons expp = diff_ex(
                subject,
                (Polygons)new_surfaces
            );

            new_surfaces.append(expp, *g.front());
        }
    }

    this->fill_surfaces = std::move(new_surfaces);
}

/// If no solid layers are requested, turns top/bottom surfaces to internal
/// Turns too small internal regions into solid regions according to the user setting
void
LayerRegion::prepare_fill_surfaces()
{
    /*  Note: in order to make the psPrepareInfill step idempotent, we should never
        alter fill_surfaces boundaries on which our idempotency relies since that's
        the only meaningful information returned by psPerimeters. */

    // if no solid layers are requested, turn top/bottom surfaces to internal
    if (this->region()->config.top_solid_layers == 0 && this->region()->config.min_top_bottom_shell_thickness <= 0) {
        for (Surface &surface : this->fill_surfaces.surfaces) {
            if (surface.surface_type == stTop) {
                if (this->layer()->object()->config.infill_only_where_needed) {
                    surface.surface_type = (stInternal | stVoid);
                } else {
                    surface.surface_type = stInternal;
                }
            }
        }
    }

    if (this->region()->config.bottom_solid_layers == 0 && this->region()->config.min_top_bottom_shell_thickness <= 0) {
        for (Surface &surface : this->fill_surfaces.surfaces) {
            if (surface.is_bottom())
                surface.surface_type = stInternal;
        }
    }

    // turn too small internal regions into solid regions according to the user setting
    const float &fill_density = this->region()->config.fill_density;
    if (fill_density > 0 && fill_density < 100) {
        // scaling an area requires two calls!
        // (we don't use scale_() because it would overflow the coord_t range
        const double min_area = this->region()->config.solid_infill_below_area.value / SCALING_FACTOR / SCALING_FACTOR;
        for (Surface &surface : this->fill_surfaces.surfaces) {
            if (!surface.is_internal() && surface.area() <= min_area)
                surface.surface_type = (stInternal | stSolid);
        }
    }
}

///  Gets smallest area by squaring the Flow's scaled spacing
double
LayerRegion::infill_area_threshold() const
{
    double ss = this->flow(frSolidInfill).scaled_spacing();
    return ss*ss;
}

}
<|endoftext|>