<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

#ifdef HAVE_PNG

/****************************************************************************************\
    This part of the file implements PNG codec on base of libpng library,
    in particular, this code is based on example.c from libpng
    (see otherlibs/_graphics/readme.txt for copyright notice)
    and png2bmp sample from libpng distribution (Copyright (C) 1999-2001 MIYASAKA Masaru)
\****************************************************************************************/

#ifdef HAVE_LIBPNG_PNG_H
#include <libpng/png.h>
#else
#include <png.h>
#endif
#include "grfmt_png.hpp"

namespace cv
{

/////////////////////// PngDecoder ///////////////////

PngDecoder::PngDecoder()
{
    m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
    m_color_type = 0;
    m_png_ptr = 0;
    m_info_ptr = m_end_info = 0;
    m_f = 0;
    m_buf_supported = true;
    m_buf_pos = 0;
}

PngDecoder::~PngDecoder()
{
    close();
}

ImageDecoder PngDecoder::newDecoder() const
{
    return new PngDecoder;
}

void  PngDecoder::close()
{
    if( m_f )
    {
        fclose( m_f );
        m_f = 0;
    }

    if( m_png_ptr )
    {
        png_structp png_ptr = (png_structp)m_png_ptr;
        png_infop info_ptr = (png_infop)m_info_ptr;
        png_infop end_info = (png_infop)m_end_info;
        png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
        m_png_ptr = m_info_ptr = m_end_info = 0;
    }
}

void  PngDecoder::readDataFromBuf( void* _png_ptr, uchar* dst, size_t size )
{
    png_structp png_ptr = (png_structp)_png_ptr;
    PngDecoder* decoder = (PngDecoder*)(png_get_io_ptr(png_ptr));
    CV_Assert( decoder );
    const Mat& buf = decoder->m_buf;
    if( decoder->m_buf_pos + size > buf.cols*buf.rows*buf.elemSize() )
    {
        png_error(png_ptr, "PNG input buffer is incomplete");
        return;
    }
    memcpy( dst, &decoder->m_buf.data[decoder->m_buf_pos], size );
    decoder->m_buf_pos += size;
}

bool  PngDecoder::readHeader()
{
    bool result = false;
    close();

    png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );

    if( png_ptr )
    {
        png_infop info_ptr = png_create_info_struct( png_ptr );
        png_infop end_info = png_create_info_struct( png_ptr );

        m_png_ptr = png_ptr;
        m_info_ptr = info_ptr;
        m_end_info = end_info;
        m_buf_pos = 0;

        if( info_ptr && end_info )
        {
            if( setjmp( png_jmpbuf( png_ptr ) ) == 0 )
            {
                if( !m_buf.empty() )
                    png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
                else
                {
                    m_f = fopen( m_filename.c_str(), "rb" );
                    if( m_f )
                        png_init_io( png_ptr, m_f );
                }

                if( !m_buf.empty() || m_f )
                {
                    png_uint_32 width, height;
                    int bit_depth, color_type;

                    png_read_info( png_ptr, info_ptr );

                    png_get_IHDR( png_ptr, info_ptr, &width, &height,
                                  &bit_depth, &color_type, 0, 0, 0 );

                    m_width = (int)width;
                    m_height = (int)height;
                    m_color_type = color_type;
                    m_bit_depth = bit_depth;

                    if( bit_depth <= 8 || bit_depth == 16 )
                    {
                        m_type = color_type == PNG_COLOR_TYPE_RGB ||
                             color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                             color_type == PNG_COLOR_TYPE_PALETTE ? CV_8UC3 : CV_8UC1;
                        if( bit_depth == 16 )
                            m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
                        result = true;
                    }
                }
            }
        }
    }

    if( !result )
        close();

    return result;
}

bool  PngDecoder::readData( Mat& img )
{
    bool result = false;
    AutoBuffer<uchar*> _buffer(m_height);
    uchar** buffer = _buffer;
    int color = img.channels() > 1;
    uchar* data = img.data;
    int step = (int)img.step;

    if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
    {
        png_structp png_ptr = (png_structp)m_png_ptr;
        png_infop info_ptr = (png_infop)m_info_ptr;
        png_infop end_info = (png_infop)m_end_info;

        if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
        {
            int y;

            if( img.depth() == CV_8U && m_bit_depth == 16 )
                png_set_strip_16( png_ptr );
            else if( !isBigEndian() )
                png_set_swap( png_ptr );

            /* observation: png_read_image() writes 400 bytes beyond
             * end of data when reading a 400x118 color png
             * "mpplus_sand.png".  OpenCV crashes even with demo
             * programs.  Looking at the loaded image I'd say we get 4
             * bytes per pixel instead of 3 bytes per pixel.  Test
             * indicate that it is a good idea to always ask for
             * stripping alpha..  18.11.2004 Axel Walthelm
             */
            png_set_strip_alpha( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_PALETTE )
                png_set_palette_to_rgb( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
#if PNG_LIBPNG_VER_MAJOR*100 + PNG_LIBPNG_VER_MINOR >= 104
                png_set_expand_gray_1_2_4_to_8( png_ptr );
#else
                png_set_gray_1_2_4_to_8( png_ptr );
#endif

            if( CV_MAT_CN(m_type) > 1 && color )
                png_set_bgr( png_ptr ); // convert RGB to BGR
            else if( color )
                png_set_gray_to_rgb( png_ptr ); // Gray->RGB
            else
                png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray

            png_read_update_info( png_ptr, info_ptr );

            for( y = 0; y < m_height; y++ )
                buffer[y] = data + y*step;

            png_read_image( png_ptr, buffer );
            png_read_end( png_ptr, end_info );

            result = true;
        }
    }

    close();
    return result;
}

/////////////////////// PngEncoder ///////////////////

PngEncoder::PngEncoder()
{
    m_description = "Portable Network Graphics files (*.png)";
    m_buf_supported = true;
}

PngEncoder::~PngEncoder()
{
}

bool  PngEncoder::isFormatSupported( int depth ) const
{
    return depth == CV_8U || depth == CV_16U;
}

ImageEncoder PngEncoder::newEncoder() const
{
    return new PngEncoder;
}

void PngEncoder::writeDataToBuf(void* _png_ptr, uchar* src, size_t size)
{
    if( size == 0 )
        return;
    png_structp png_ptr = (png_structp)_png_ptr;
    PngEncoder* encoder = (PngEncoder*)(png_get_io_ptr(png_ptr));
    CV_Assert( encoder && encoder->m_buf );
    size_t cursz = encoder->m_buf->size();
    encoder->m_buf->resize(cursz + size);
    memcpy( &(*encoder->m_buf)[cursz], src, size );
}

void PngEncoder::flushBuf(void*)
{
}

bool  PngEncoder::write( const Mat& img, const vector<int>& params )
{
    int compression_level = 0;

    for( size_t i = 0; i < params.size(); i += 2 )
    {
        if( params[i] == CV_IMWRITE_PNG_COMPRESSION )
        {
            compression_level = params[i+1];
            compression_level = MIN(MAX(compression_level, 0), MAX_MEM_LEVEL);
        }
    }

    png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    png_infop info_ptr = 0;
    FILE* f = 0;
    int y, width = img.cols, height = img.rows;
    int depth = img.depth(), channels = img.channels();
    bool result = false;
    AutoBuffer<uchar*> buffer;

    if( depth != CV_8U && depth != CV_16U )
        return false;

    if( png_ptr )
    {
        info_ptr = png_create_info_struct( png_ptr );

        if( info_ptr )
        {
            if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
            {
                if( m_buf )
                {
                    png_set_write_fn(png_ptr, this,
                        (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf);
                }
                else
                {
                    f = fopen( m_filename.c_str(), "wb" );
                    if( f )
                        png_init_io( png_ptr, f );
                }

                if( m_buf || f )
                {
                    if( compression_level > 0 )
                    {
                        png_set_compression_mem_level( png_ptr, compression_level );
                    }
                    else
                    {
                        // tune parameters for speed
                        // (see http://wiki.linuxquestions.org/wiki/Libpng)
                        png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
                        png_set_compression_level(png_ptr, Z_BEST_SPEED);
                    }
                    png_set_compression_strategy(png_ptr, Z_HUFFMAN_ONLY);

                    png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? 8 : 16,
                        channels == 1 ? PNG_COLOR_TYPE_GRAY :
                        channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
                        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                        PNG_FILTER_TYPE_DEFAULT );

                    png_write_info( png_ptr, info_ptr );

                    png_set_bgr( png_ptr );
                    if( !isBigEndian() )
                        png_set_swap( png_ptr );

                    buffer.allocate(height);
                    for( y = 0; y < height; y++ )
                        buffer[y] = img.data + y*img.step;

                    png_write_image( png_ptr, buffer );
                    png_write_end( png_ptr, info_ptr );

                    result = true;
                }
            }
        }
    }

    png_destroy_write_struct( &png_ptr, &info_ptr );
    if(f) fclose( f );

    return result;
}

}

#endif

/* End of file. */
<commit_msg>fixed Xcode 4.1 compile errors in png codec in highgui<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

#ifdef HAVE_PNG

/****************************************************************************************\
    This part of the file implements PNG codec on base of libpng library,
    in particular, this code is based on example.c from libpng
    (see otherlibs/_graphics/readme.txt for copyright notice)
    and png2bmp sample from libpng distribution (Copyright (C) 1999-2001 MIYASAKA Masaru)
\****************************************************************************************/

#ifdef HAVE_LIBPNG_PNG_H
#include <libpng/png.h>
#else
#include <png.h>
#endif
#include <zlib.h>
#include "grfmt_png.hpp"

namespace cv
{

/////////////////////// PngDecoder ///////////////////

PngDecoder::PngDecoder()
{
    m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
    m_color_type = 0;
    m_png_ptr = 0;
    m_info_ptr = m_end_info = 0;
    m_f = 0;
    m_buf_supported = true;
    m_buf_pos = 0;
}

PngDecoder::~PngDecoder()
{
    close();
}

ImageDecoder PngDecoder::newDecoder() const
{
    return new PngDecoder;
}

void  PngDecoder::close()
{
    if( m_f )
    {
        fclose( m_f );
        m_f = 0;
    }

    if( m_png_ptr )
    {
        png_structp png_ptr = (png_structp)m_png_ptr;
        png_infop info_ptr = (png_infop)m_info_ptr;
        png_infop end_info = (png_infop)m_end_info;
        png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
        m_png_ptr = m_info_ptr = m_end_info = 0;
    }
}

void  PngDecoder::readDataFromBuf( void* _png_ptr, uchar* dst, size_t size )
{
    png_structp png_ptr = (png_structp)_png_ptr;
    PngDecoder* decoder = (PngDecoder*)(png_get_io_ptr(png_ptr));
    CV_Assert( decoder );
    const Mat& buf = decoder->m_buf;
    if( decoder->m_buf_pos + size > buf.cols*buf.rows*buf.elemSize() )
    {
        png_error(png_ptr, "PNG input buffer is incomplete");
        return;
    }
    memcpy( dst, &decoder->m_buf.data[decoder->m_buf_pos], size );
    decoder->m_buf_pos += size;
}

bool  PngDecoder::readHeader()
{
    bool result = false;
    close();

    png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );

    if( png_ptr )
    {
        png_infop info_ptr = png_create_info_struct( png_ptr );
        png_infop end_info = png_create_info_struct( png_ptr );

        m_png_ptr = png_ptr;
        m_info_ptr = info_ptr;
        m_end_info = end_info;
        m_buf_pos = 0;

        if( info_ptr && end_info )
        {
            if( setjmp( png_jmpbuf( png_ptr ) ) == 0 )
            {
                if( !m_buf.empty() )
                    png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
                else
                {
                    m_f = fopen( m_filename.c_str(), "rb" );
                    if( m_f )
                        png_init_io( png_ptr, m_f );
                }

                if( !m_buf.empty() || m_f )
                {
                    png_uint_32 width, height;
                    int bit_depth, color_type;

                    png_read_info( png_ptr, info_ptr );

                    png_get_IHDR( png_ptr, info_ptr, &width, &height,
                                  &bit_depth, &color_type, 0, 0, 0 );

                    m_width = (int)width;
                    m_height = (int)height;
                    m_color_type = color_type;
                    m_bit_depth = bit_depth;

                    if( bit_depth <= 8 || bit_depth == 16 )
                    {
                        m_type = color_type == PNG_COLOR_TYPE_RGB ||
                             color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                             color_type == PNG_COLOR_TYPE_PALETTE ? CV_8UC3 : CV_8UC1;
                        if( bit_depth == 16 )
                            m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
                        result = true;
                    }
                }
            }
        }
    }

    if( !result )
        close();

    return result;
}

bool  PngDecoder::readData( Mat& img )
{
    bool result = false;
    AutoBuffer<uchar*> _buffer(m_height);
    uchar** buffer = _buffer;
    int color = img.channels() > 1;
    uchar* data = img.data;
    int step = (int)img.step;

    if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
    {
        png_structp png_ptr = (png_structp)m_png_ptr;
        png_infop info_ptr = (png_infop)m_info_ptr;
        png_infop end_info = (png_infop)m_end_info;

        if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
        {
            int y;

            if( img.depth() == CV_8U && m_bit_depth == 16 )
                png_set_strip_16( png_ptr );
            else if( !isBigEndian() )
                png_set_swap( png_ptr );

            /* observation: png_read_image() writes 400 bytes beyond
             * end of data when reading a 400x118 color png
             * "mpplus_sand.png".  OpenCV crashes even with demo
             * programs.  Looking at the loaded image I'd say we get 4
             * bytes per pixel instead of 3 bytes per pixel.  Test
             * indicate that it is a good idea to always ask for
             * stripping alpha..  18.11.2004 Axel Walthelm
             */
            png_set_strip_alpha( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_PALETTE )
                png_set_palette_to_rgb( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
#if PNG_LIBPNG_VER_MAJOR*100 + PNG_LIBPNG_VER_MINOR >= 104
                png_set_expand_gray_1_2_4_to_8( png_ptr );
#else
                png_set_gray_1_2_4_to_8( png_ptr );
#endif

            if( CV_MAT_CN(m_type) > 1 && color )
                png_set_bgr( png_ptr ); // convert RGB to BGR
            else if( color )
                png_set_gray_to_rgb( png_ptr ); // Gray->RGB
            else
                png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray

            png_read_update_info( png_ptr, info_ptr );

            for( y = 0; y < m_height; y++ )
                buffer[y] = data + y*step;

            png_read_image( png_ptr, buffer );
            png_read_end( png_ptr, end_info );

            result = true;
        }
    }

    close();
    return result;
}

/////////////////////// PngEncoder ///////////////////

PngEncoder::PngEncoder()
{
    m_description = "Portable Network Graphics files (*.png)";
    m_buf_supported = true;
}

PngEncoder::~PngEncoder()
{
}

bool  PngEncoder::isFormatSupported( int depth ) const
{
    return depth == CV_8U || depth == CV_16U;
}

ImageEncoder PngEncoder::newEncoder() const
{
    return new PngEncoder;
}

void PngEncoder::writeDataToBuf(void* _png_ptr, uchar* src, size_t size)
{
    if( size == 0 )
        return;
    png_structp png_ptr = (png_structp)_png_ptr;
    PngEncoder* encoder = (PngEncoder*)(png_get_io_ptr(png_ptr));
    CV_Assert( encoder && encoder->m_buf );
    size_t cursz = encoder->m_buf->size();
    encoder->m_buf->resize(cursz + size);
    memcpy( &(*encoder->m_buf)[cursz], src, size );
}

void PngEncoder::flushBuf(void*)
{
}

bool  PngEncoder::write( const Mat& img, const vector<int>& params )
{
    int compression_level = 0;

    for( size_t i = 0; i < params.size(); i += 2 )
    {
        if( params[i] == CV_IMWRITE_PNG_COMPRESSION )
        {
            compression_level = params[i+1];
            compression_level = MIN(MAX(compression_level, 0), MAX_MEM_LEVEL);
        }
    }

    png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    png_infop info_ptr = 0;
    FILE* f = 0;
    int y, width = img.cols, height = img.rows;
    int depth = img.depth(), channels = img.channels();
    bool result = false;
    AutoBuffer<uchar*> buffer;

    if( depth != CV_8U && depth != CV_16U )
        return false;

    if( png_ptr )
    {
        info_ptr = png_create_info_struct( png_ptr );

        if( info_ptr )
        {
            if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
            {
                if( m_buf )
                {
                    png_set_write_fn(png_ptr, this,
                        (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf);
                }
                else
                {
                    f = fopen( m_filename.c_str(), "wb" );
                    if( f )
                        png_init_io( png_ptr, f );
                }

                if( m_buf || f )
                {
                    if( compression_level > 0 )
                    {
                        png_set_compression_mem_level( png_ptr, compression_level );
                    }
                    else
                    {
                        // tune parameters for speed
                        // (see http://wiki.linuxquestions.org/wiki/Libpng)
                        png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
                        png_set_compression_level(png_ptr, Z_BEST_SPEED);
                    }
                    png_set_compression_strategy(png_ptr, Z_HUFFMAN_ONLY);

                    png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? 8 : 16,
                        channels == 1 ? PNG_COLOR_TYPE_GRAY :
                        channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
                        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                        PNG_FILTER_TYPE_DEFAULT );

                    png_write_info( png_ptr, info_ptr );

                    png_set_bgr( png_ptr );
                    if( !isBigEndian() )
                        png_set_swap( png_ptr );

                    buffer.allocate(height);
                    for( y = 0; y < height; y++ )
                        buffer[y] = img.data + y*img.step;

                    png_write_image( png_ptr, buffer );
                    png_write_end( png_ptr, info_ptr );

                    result = true;
                }
            }
        }
    }

    png_destroy_write_struct( &png_ptr, &info_ptr );
    if(f) fclose( f );

    return result;
}

}

#endif

/* End of file. */
<|endoftext|>


<commit_before>/*
* ECDSA implemenation
* (C) 2007 Manuel Hartl, FlexSecure GmbH
*     2007 Falko Strenzke, FlexSecure GmbH
*     2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/ecdsa.h>
#include <botan/numthry.h>
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/secmem.h>
#include <botan/point_gfp.h>

namespace Botan {

ECDSA_PrivateKey::ECDSA_PrivateKey(RandomNumberGenerator& rng,
                                   const EC_Domain_Params& dom_pars)
   {
   mp_dom_pars = std::unique_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_pars));
   generate_private_key(rng);

   try
      {
      mp_public_point->check_invariants();
      }
   catch(Illegal_Point& e)
      {
      throw Invalid_State("ECDSA key generation failed");
      }

   m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point);
   }

ECDSA_PrivateKey::ECDSA_PrivateKey(const EC_Domain_Params& domain,
                                   const BigInt& x)
   {
   mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(domain));

   m_private_value = x;
   mp_public_point = std::auto_ptr<PointGFp>(new PointGFp (mp_dom_pars->get_base_point()));
   mp_public_point->mult_this_secure(m_private_value,
                                     mp_dom_pars->get_order(),
                                     mp_dom_pars->get_order()-1);

   try
      {
      mp_public_point->check_invariants();
      }
   catch(Illegal_Point& e)
      {
      throw Invalid_State("ECDSA key generation failed");
      }

   m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point);
   }

/*
* ECDSA_PublicKey
*/
void ECDSA_PublicKey::affirm_init() const // virtual
   {
   EC_PublicKey::affirm_init();
   }

void ECDSA_PublicKey::set_domain_parameters(const EC_Domain_Params& dom_pars)
   {
   if(mp_dom_pars.get())
      {
      // they are already set, we must ensure that they are equal to the arg
      if(dom_pars != *mp_dom_pars.get())
         throw Invalid_Argument("EC_PublicKey::set_domain_parameters - cannot reset to a new value");

      return;
      }

   if(m_enc_public_point.size() == 0)
      throw Invalid_State("EC_PublicKey::set_domain_parameters(): encoded public point isn't set");

   // now try to decode the public key ...
   PointGFp tmp_pp(OS2ECP(m_enc_public_point, dom_pars.get_curve()));
   try
      {
      tmp_pp.check_invariants();
      }
   catch(Illegal_Point e)
      {
      throw Invalid_State("EC_PublicKey::set_domain_parameters(): point does not lie on provided curve");
      }

   mp_dom_pars.reset(new EC_Domain_Params(dom_pars));
   ECDSA_Core tmp_ecdsa_core(*mp_dom_pars, BigInt(0), tmp_pp);
   mp_public_point.reset(new PointGFp(tmp_pp));
   m_ecdsa_core = tmp_ecdsa_core;
   }

void ECDSA_PublicKey::set_all_values(const ECDSA_PublicKey& other)
   {
   m_param_enc = other.m_param_enc;
   m_ecdsa_core = other.m_ecdsa_core;
   m_enc_public_point = other.m_enc_public_point;
   if(other.mp_dom_pars.get())
      mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters()));

   if(other.mp_public_point.get())
      mp_public_point.reset(new PointGFp(other.public_point()));
   }

ECDSA_PublicKey::ECDSA_PublicKey(const ECDSA_PublicKey& other)
   : Public_Key(),
     EC_PublicKey(),
     PK_Verifying_wo_MR_Key()
   {
   set_all_values(other);
   }

const ECDSA_PublicKey& ECDSA_PublicKey::operator=(const ECDSA_PublicKey& rhs)
   {
   set_all_values(rhs);
   return *this;
   }

bool ECDSA_PublicKey::verify(const byte msg[], u32bit msg_len,
                             const byte sig[], u32bit sig_len) const
   {
   affirm_init();

   return m_ecdsa_core.verify(msg, msg_len, sig, sig_len);
   }

ECDSA_PublicKey::ECDSA_PublicKey(const EC_Domain_Params& dom_par,
                                 const PointGFp& public_point)
   {
   mp_dom_pars = std::unique_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_par));
   mp_public_point = std::unique_ptr<PointGFp>(new PointGFp(public_point));
   m_param_enc = ENC_EXPLICIT;
   m_ecdsa_core = ECDSA_Core(*mp_dom_pars, BigInt(0), *mp_public_point);
   }

void ECDSA_PublicKey::X509_load_hook()
   {
   EC_PublicKey::X509_load_hook();
   EC_PublicKey::affirm_init();
   m_ecdsa_core = ECDSA_Core ( *mp_dom_pars, BigInt ( 0 ), *mp_public_point );
   }

u32bit ECDSA_PublicKey::max_input_bits() const
   {
   if(!mp_dom_pars.get())
      {
      throw Invalid_State("ECDSA_PublicKey::max_input_bits(): domain parameters not set");
      }
   return mp_dom_pars->get_order().bits();
   }

/*************************
* ECDSA_PrivateKey
*************************/
void ECDSA_PrivateKey::affirm_init() const // virtual
   {
   EC_PrivateKey::affirm_init();
   }

void ECDSA_PrivateKey::PKCS8_load_hook(bool generated)
   {
   EC_PrivateKey::PKCS8_load_hook(generated);
   EC_PrivateKey::affirm_init();
   m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point);
   }

void ECDSA_PrivateKey::set_all_values(const ECDSA_PrivateKey& other)
   {
   m_private_value = other.m_private_value;
   m_param_enc = other.m_param_enc;
   m_ecdsa_core = other.m_ecdsa_core;
   m_enc_public_point = other.m_enc_public_point;

   if(other.mp_dom_pars.get())
      mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters()));

   if(other.mp_public_point.get())
      mp_public_point.reset(new PointGFp(other.public_point()));
   }

ECDSA_PrivateKey::ECDSA_PrivateKey(ECDSA_PrivateKey const& other)
   : Public_Key(),
     EC_PublicKey(),
     Private_Key(),
     ECDSA_PublicKey(),
     EC_PrivateKey(),
     PK_Signing_Key()
   {
   set_all_values(other);
   }

const ECDSA_PrivateKey& ECDSA_PrivateKey::operator=(const ECDSA_PrivateKey& rhs)
   {
   set_all_values(rhs);
   return *this;
   }

SecureVector<byte> ECDSA_PrivateKey::sign(const byte msg[],
                                          u32bit msg_len,
                                          RandomNumberGenerator& rng) const
   {
   affirm_init();

   const BigInt& n = mp_dom_pars->get_order();

   BigInt k;
   do
      k.randomize(rng, n.bits()-1);
   while(k >= n);

   return m_ecdsa_core.sign(msg, msg_len, k);
   }

}
<commit_msg>auto_ptr is unique_ptr in C++0x<commit_after>/*
* ECDSA implemenation
* (C) 2007 Manuel Hartl, FlexSecure GmbH
*     2007 Falko Strenzke, FlexSecure GmbH
*     2008 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/ecdsa.h>
#include <botan/numthry.h>
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/secmem.h>
#include <botan/point_gfp.h>

namespace Botan {

ECDSA_PrivateKey::ECDSA_PrivateKey(RandomNumberGenerator& rng,
                                   const EC_Domain_Params& dom_pars)
   {
   mp_dom_pars = std::unique_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_pars));
   generate_private_key(rng);

   try
      {
      mp_public_point->check_invariants();
      }
   catch(Illegal_Point& e)
      {
      throw Invalid_State("ECDSA key generation failed");
      }

   m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point);
   }

ECDSA_PrivateKey::ECDSA_PrivateKey(const EC_Domain_Params& domain,
                                   const BigInt& x)
   {
   mp_dom_pars = std::unique_ptr<EC_Domain_Params>(new EC_Domain_Params(domain));

   m_private_value = x;
   mp_public_point = std::unique_ptr<PointGFp>(new PointGFp (mp_dom_pars->get_base_point()));
   mp_public_point->mult_this_secure(m_private_value,
                                     mp_dom_pars->get_order(),
                                     mp_dom_pars->get_order()-1);

   try
      {
      mp_public_point->check_invariants();
      }
   catch(Illegal_Point& e)
      {
      throw Invalid_State("ECDSA key generation failed");
      }

   m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point);
   }

/*
* ECDSA_PublicKey
*/
void ECDSA_PublicKey::affirm_init() const // virtual
   {
   EC_PublicKey::affirm_init();
   }

void ECDSA_PublicKey::set_domain_parameters(const EC_Domain_Params& dom_pars)
   {
   if(mp_dom_pars.get())
      {
      // they are already set, we must ensure that they are equal to the arg
      if(dom_pars != *mp_dom_pars.get())
         throw Invalid_Argument("EC_PublicKey::set_domain_parameters - cannot reset to a new value");

      return;
      }

   if(m_enc_public_point.size() == 0)
      throw Invalid_State("EC_PublicKey::set_domain_parameters(): encoded public point isn't set");

   // now try to decode the public key ...
   PointGFp tmp_pp(OS2ECP(m_enc_public_point, dom_pars.get_curve()));
   try
      {
      tmp_pp.check_invariants();
      }
   catch(Illegal_Point e)
      {
      throw Invalid_State("EC_PublicKey::set_domain_parameters(): point does not lie on provided curve");
      }

   mp_dom_pars.reset(new EC_Domain_Params(dom_pars));
   ECDSA_Core tmp_ecdsa_core(*mp_dom_pars, BigInt(0), tmp_pp);
   mp_public_point.reset(new PointGFp(tmp_pp));
   m_ecdsa_core = tmp_ecdsa_core;
   }

void ECDSA_PublicKey::set_all_values(const ECDSA_PublicKey& other)
   {
   m_param_enc = other.m_param_enc;
   m_ecdsa_core = other.m_ecdsa_core;
   m_enc_public_point = other.m_enc_public_point;
   if(other.mp_dom_pars.get())
      mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters()));

   if(other.mp_public_point.get())
      mp_public_point.reset(new PointGFp(other.public_point()));
   }

ECDSA_PublicKey::ECDSA_PublicKey(const ECDSA_PublicKey& other)
   : Public_Key(),
     EC_PublicKey(),
     PK_Verifying_wo_MR_Key()
   {
   set_all_values(other);
   }

const ECDSA_PublicKey& ECDSA_PublicKey::operator=(const ECDSA_PublicKey& rhs)
   {
   set_all_values(rhs);
   return *this;
   }

bool ECDSA_PublicKey::verify(const byte msg[], u32bit msg_len,
                             const byte sig[], u32bit sig_len) const
   {
   affirm_init();

   return m_ecdsa_core.verify(msg, msg_len, sig, sig_len);
   }

ECDSA_PublicKey::ECDSA_PublicKey(const EC_Domain_Params& dom_par,
                                 const PointGFp& public_point)
   {
   mp_dom_pars = std::unique_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_par));
   mp_public_point = std::unique_ptr<PointGFp>(new PointGFp(public_point));
   m_param_enc = ENC_EXPLICIT;
   m_ecdsa_core = ECDSA_Core(*mp_dom_pars, BigInt(0), *mp_public_point);
   }

void ECDSA_PublicKey::X509_load_hook()
   {
   EC_PublicKey::X509_load_hook();
   EC_PublicKey::affirm_init();
   m_ecdsa_core = ECDSA_Core ( *mp_dom_pars, BigInt ( 0 ), *mp_public_point );
   }

u32bit ECDSA_PublicKey::max_input_bits() const
   {
   if(!mp_dom_pars.get())
      {
      throw Invalid_State("ECDSA_PublicKey::max_input_bits(): domain parameters not set");
      }
   return mp_dom_pars->get_order().bits();
   }

/*************************
* ECDSA_PrivateKey
*************************/
void ECDSA_PrivateKey::affirm_init() const // virtual
   {
   EC_PrivateKey::affirm_init();
   }

void ECDSA_PrivateKey::PKCS8_load_hook(bool generated)
   {
   EC_PrivateKey::PKCS8_load_hook(generated);
   EC_PrivateKey::affirm_init();
   m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point);
   }

void ECDSA_PrivateKey::set_all_values(const ECDSA_PrivateKey& other)
   {
   m_private_value = other.m_private_value;
   m_param_enc = other.m_param_enc;
   m_ecdsa_core = other.m_ecdsa_core;
   m_enc_public_point = other.m_enc_public_point;

   if(other.mp_dom_pars.get())
      mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters()));

   if(other.mp_public_point.get())
      mp_public_point.reset(new PointGFp(other.public_point()));
   }

ECDSA_PrivateKey::ECDSA_PrivateKey(ECDSA_PrivateKey const& other)
   : Public_Key(),
     EC_PublicKey(),
     Private_Key(),
     ECDSA_PublicKey(),
     EC_PrivateKey(),
     PK_Signing_Key()
   {
   set_all_values(other);
   }

const ECDSA_PrivateKey& ECDSA_PrivateKey::operator=(const ECDSA_PrivateKey& rhs)
   {
   set_all_values(rhs);
   return *this;
   }

SecureVector<byte> ECDSA_PrivateKey::sign(const byte msg[],
                                          u32bit msg_len,
                                          RandomNumberGenerator& rng) const
   {
   affirm_init();

   const BigInt& n = mp_dom_pars->get_order();

   BigInt k;
   do
      k.randomize(rng, n.bits()-1);
   while(k >= n);

   return m_ecdsa_core.sign(msg, msg_len, k);
   }

}
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2020                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#ifdef WIN32

#include <modules/touch/include/win32_touch.h>

#include <openspace/engine/globals.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/windowdelegate.h>
#include <ghoul/logging/logmanager.h>
#include <TUIO/TuioServer.h>
#include <chrono>
#include <thread>
#include <tchar.h>
#include <tpcshrd.h>

// #define ENABLE_TUIOMESSAGES
#define ENABLE_DIRECTMSG

namespace {
    using namespace std::chrono;
    constexpr const char* _loggerCat = "win32_touch";
    HHOOK gTouchHook = nullptr;
    std::thread* gMouseHookThread;
    HHOOK gMouseHook = nullptr;
    bool gStarted = false;
    microseconds gStartTime = microseconds(0);
    const long long gFrequency = []() -> long long {
      LARGE_INTEGER frequency;
      QueryPerformanceFrequency(&frequency);
      return frequency.QuadPart;
    }();
    std::unordered_map<
        UINT32,
        std::unique_ptr<openspace::TouchInputHolder>
    > gTouchInputsMap;
#ifdef ENABLE_TUIOMESSAGES
    TUIO::TuioServer* gTuioServer = nullptr;
    std::unordered_map<UINT, TUIO::TuioCursor*> gCursorMap;
#endif
} // namespace

namespace openspace {
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);

// This hook will only work for Win8+ Digitizers.
// - Once GLFW has native touch support, we can remove this windows-specific code
LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode != HC_ACTION) {
        return CallNextHookEx(0, nCode, wParam, lParam);
    }

    LPMSG pStruct = reinterpret_cast<LPMSG>(lParam);
    const UINT message = pStruct->message;
    switch (message) {
        case WM_POINTERDOWN:
        case WM_POINTERUPDATE:
        case WM_POINTERUP:
        {
            POINTER_INFO info = {};
            BOOL hasInfo = GetPointerInfo(GET_POINTERID_WPARAM(pStruct->wParam), &info);
            if (!hasInfo) {
                break;
            }

            //Implementation from microsoft STL of high_resolution_clock(steady_clock):
            const long long freq = gFrequency;
            const long long whole = (info.PerformanceCount / freq) * std::micro::den;
            const long long part  = (info.PerformanceCount % freq) *
                                    std::micro::den / freq;
            const microseconds timestamp =
                duration<UINT64, std::micro>(whole + part) - gStartTime;

            RECT rect;
            GetClientRect(pStruct->hwnd, reinterpret_cast<LPRECT>(&rect));

            POINT p = info.ptPixelLocation;
            // native touch to screen conversion
            ScreenToClient(pStruct->hwnd, reinterpret_cast<LPPOINT>(&p));

            float xPos = static_cast<float>(p.x) /
                         static_cast<float>(rect.right - rect.left);
            float yPos = static_cast<float>(p.y) /
                         static_cast<float>(rect.bottom - rect.top);

            TouchInput touchInput(
                reinterpret_cast<size_t>(info.sourceDevice),
                static_cast<size_t>(info.pointerId),
                xPos,
                yPos,
                static_cast<double>(timestamp.count()) / 1'000'000.0
            );

            if (info.pointerFlags & POINTER_FLAG_DOWN) {
#ifdef ENABLE_DIRECTMSG
                std::unique_ptr<TouchInputHolder> points =
                    std::make_unique<TouchInputHolder>(touchInput);
                gTouchInputsMap.emplace(info.pointerId, std::move(points));
                global::openSpaceEngine.touchDetectionCallback(touchInput);
#endif
#ifdef ENABLE_TUIOMESSAGES
                // Handle new touchpoint
                gTuioServer->initFrame(TUIO::TuioTime::getSessionTime());
                gCursorMap[info.pointerId] = gTuioServer->addTuioCursor(
                    xPos,
                    yPos
                );
                gTuioServer->commitFrame();
#endif
            }
            else if (info.pointerFlags & POINTER_FLAG_UPDATE) {
                // Handle update of touchpoint
#ifdef ENABLE_DIRECTMSG
                TouchInputHolder* points = gTouchInputsMap[info.pointerId].get();

                if (points->tryAddInput(touchInput)) {
                    global::openSpaceEngine.touchUpdateCallback(points->latestInput());
                }
#endif
#ifdef ENABLE_TUIOMESSAGES
                TUIO::TuioTime frameTime = TUIO::TuioTime::getSessionTime();
                if (gCursorMap[info.pointerId]->getTuioTime() == frameTime) {
                    break;
                }
                gTuioServer->initFrame(frameTime);
                gTuioServer->updateTuioCursor(gCursorMap[info.pointerId], xPos, yPos);
                gTuioServer->commitFrame();
#endif
            }
            else if (info.pointerFlags & POINTER_FLAG_UP) {
#ifdef ENABLE_DIRECTMSG
                gTouchInputsMap.erase(info.pointerId);
                global::openSpaceEngine.touchExitCallback(touchInput);
#endif
#ifdef ENABLE_TUIOMESSAGES
                // Handle removed touchpoint
                gTuioServer->initFrame(TUIO::TuioTime::getSessionTime());
                gTuioServer->removeTuioCursor(gCursorMap[info.pointerId]);
                gTuioServer->commitFrame();
                gCursorMap.erase(info.pointerId);
#endif
            }
            break;
        }
    }

    // Pass the hook along!
    return CallNextHookEx(0, nCode, wParam, lParam);
}

Win32TouchHook::Win32TouchHook(void* nativeWindow)
{
    HWND hWnd = reinterpret_cast<HWND>(nativeWindow);
    if (hWnd == nullptr) {
        LINFO("No windowhandle available for touch input.");
        return;
    }

    // HACK: This hack is required as long as our GLFW version is based on the touch
    // branch. There is no convenient way to set a GLFWBool (uint32_t) which sets the
    // state of touch-to-mouseinput interpretation. It happens to be 116 bytes into an
    // internal glfw struct...
    uint32_t* HACKY_PTR = (uint32_t *)GetPropW(hWnd, L"GLFW");
    HACKY_PTR += 116/sizeof(uint32_t);
    *HACKY_PTR = 1;

    // Test for touch:
    int value = GetSystemMetrics(SM_DIGITIZER);
    if ((value & NID_READY) == 0) {
        // Don't bother setting up touch hooks?
        return;
    }
    // stack ready, drivers installed and digitizer is ready for input
    if (value & NID_MULTI_INPUT) {
        // Digitizer is multitouch
        LINFO("Found Multitouch input digitizer!");
    }
    if (value & NID_INTEGRATED_TOUCH) {
        // Integrated touch
    }

    // This should be needed, but we seem to receive messages even without it,
    // this ought to be part to the older (< win8) windows touch-api.
    // Also - RegisterTouchWindow enables Windows gestures, which we don't want
    // since they produce visual feedback for "press-and-tap" etc.
    // RegisterTouchWindow(hWnd, TWF_FINETOUCH | TWF_WANTPALM);

    // TODO: Would be nice to find out if the gesture "press-and-tap" can be disabled
    // basically we don't really care for windows gestures for now...
    // this disables press and hold (right-click) gesture
    const UINT_PTR dwHwndTabletProperty = TABLET_DISABLE_PRESSANDHOLD;

    ATOM atom = ::GlobalAddAtom(MICROSOFT_TABLETPENSERVICE_PROPERTY);
    ::SetProp(
        hWnd,
        MICROSOFT_TABLETPENSERVICE_PROPERTY,
        reinterpret_cast<HANDLE>(dwHwndTabletProperty)
    );
    ::GlobalDeleteAtom(atom);

    if (!gStarted) {
        gStarted = true;
        gStartTime =
            duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch());
#ifdef ENABLE_TUIOMESSAGES
        gTuioServer = new TUIO::TuioServer("localhost", 3333);
        TUIO::TuioTime::initSession();
#endif
        gTouchHook = SetWindowsHookExW(
            WH_GETMESSAGE,
            HookCallback,
            GetModuleHandleW(NULL),
            GetCurrentThreadId()
        );

        // In theory, if our UI is pumped from a different thread, we can
        // handle Low-level mouse events in that thread as well.
        // this might help reduce mouse lag while running OpenSpace?
        // gMouseHookThread = new std::thread([](){
        //     gMouseHook = SetWindowsHookExW(
        //         WH_MOUSE_LL,
        //         LowLevelMouseProc,
        //         GetModuleHandleW(NULL),
        //         0 //<- Global thread id (low-level mouse is global only)
        //     );
        //     if (!gMouseHook) {
        //         LINFO("Could not setup mousehook!");
        //     }

        //     MSG msg;
        //     while (GetMessage(&msg, NULL, 0, 0)) {
        //         DispatchMessage(&msg);
        //     }
        // });

        if (!gTouchHook) {
            LINFO(fmt::format("Failed to setup WindowsHook for touch input redirection"));
#ifdef ENABLE_TUIOMESSAGES
            delete gTuioServer;
#endif
            gStarted = false;
        }
    }
}

Win32TouchHook::~Win32TouchHook() {
    if (gStarted) {
        UnhookWindowsHookEx(gTouchHook);
        UnhookWindowsHookEx(gMouseHook);
#ifdef ENABLE_TUIOMESSAGES
        delete gTuioServer;
#endif
    }
}

// Low-level mouse hook is "needed" if we want to stop mousecursor from moving
// when we get a touch-input on our window A negative effect is that this
// function is for global threads, meaning our application will cause Windows to
// stall the mouse cursor when this function can't be scheduled. This is not yet
// fail-proof...might be a race-condition on message pumping?
// - Seems to move the cursor when we get two fingers as input..
// - If we ourselves would pump windows for events, we can handle this in the
// pump-loop
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
    constexpr const LONG_PTR SIGNATURE_MASK = 0xFFFFFF00;
    constexpr const LONG_PTR MOUSEEVENTF_FROMTOUCH = 0xFF515700;
    if (nCode < 0) {
        // do not process message
        return CallNextHookEx(0, nCode, wParam, lParam);
    }
    LPMSLLHOOKSTRUCT msg = reinterpret_cast<LPMSLLHOOKSTRUCT>(lParam);
    // block injected events (in most cases generated by touches)
    bool isFromTouch = (msg->dwExtraInfo || SIGNATURE_MASK) == MOUSEEVENTF_FROMTOUCH;
    if (msg->flags & LLMHF_INJECTED || isFromTouch) {
        return 1;
    }

    // forward event
    return CallNextHookEx(0, nCode, wParam, lParam);
}

} // namespace openspace

#endif // WIN32
<commit_msg>Small code cleanup<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2020                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#ifdef WIN32

#include <modules/touch/include/win32_touch.h>

#include <openspace/engine/globals.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/windowdelegate.h>
#include <ghoul/logging/logmanager.h>
#include <TUIO/TuioServer.h>
#include <chrono>
#include <thread>
#include <tchar.h>
#include <tpcshrd.h>

// #define ENABLE_TUIOMESSAGES
#define ENABLE_DIRECTMSG

namespace {
    constexpr const char* _loggerCat = "win32_touch";
    HHOOK gTouchHook = nullptr;
    std::thread* gMouseHookThread = nullptr;
    HHOOK gMouseHook = nullptr;
    bool gStarted = false;
    std::chrono::microseconds gStartTime = std::chrono::microseconds(0);
    std::unordered_map<
        UINT32,
        std::unique_ptr<openspace::TouchInputHolder>
    > gTouchInputsMap;

#ifdef ENABLE_TUIOMESSAGES
    TUIO::TuioServer* gTuioServer = nullptr;
    std::unordered_map<UINT, TUIO::TuioCursor*> gCursorMap;
#endif

    const long long gFrequency = []() -> long long {
        LARGE_INTEGER frequency;
        QueryPerformanceFrequency(&frequency);
        return frequency.QuadPart;
    }();

} // namespace

namespace openspace {

LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);

// This hook will only work for Win8+ Digitizers.
// - Once GLFW has native touch support, we can remove this windows-specific code
LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode != HC_ACTION) {
        return CallNextHookEx(0, nCode, wParam, lParam);
    }

    LPMSG pStruct = reinterpret_cast<LPMSG>(lParam);
    const UINT message = pStruct->message;
    switch (message) {
        case WM_POINTERDOWN:
        case WM_POINTERUPDATE:
        case WM_POINTERUP:
        {
            POINTER_INFO info = {};
            BOOL hasInfo = GetPointerInfo(GET_POINTERID_WPARAM(pStruct->wParam), &info);
            if (!hasInfo) {
                break;
            }

            //Implementation from microsoft STL of high_resolution_clock(steady_clock):
            const long long freq = gFrequency;
            const long long whole = (info.PerformanceCount / freq) * std::micro::den;
            const long long part  = (info.PerformanceCount % freq) *
                                    std::micro::den / freq;
            const std::chrono::microseconds timestamp =
                std::chrono::duration<UINT64, std::micro>(whole + part) - gStartTime;

            RECT rect;
            GetClientRect(pStruct->hwnd, reinterpret_cast<LPRECT>(&rect));

            POINT p = info.ptPixelLocation;
            // native touch to screen conversion
            ScreenToClient(pStruct->hwnd, reinterpret_cast<LPPOINT>(&p));

            const float xPos = static_cast<float>(p.x) /
                               static_cast<float>(rect.right - rect.left);
            const float yPos = static_cast<float>(p.y) /
                               static_cast<float>(rect.bottom - rect.top);

            TouchInput touchInput(
                reinterpret_cast<size_t>(info.sourceDevice),
                static_cast<size_t>(info.pointerId),
                xPos,
                yPos,
                static_cast<double>(timestamp.count()) / 1000000.0
            );

            if (info.pointerFlags & POINTER_FLAG_DOWN) {
#ifdef ENABLE_DIRECTMSG
                std::unique_ptr<TouchInputHolder> points =
                    std::make_unique<TouchInputHolder>(touchInput);
                gTouchInputsMap.emplace(info.pointerId, std::move(points));
                global::openSpaceEngine.touchDetectionCallback(touchInput);
#endif
#ifdef ENABLE_TUIOMESSAGES
                // Handle new touchpoint
                gTuioServer->initFrame(TUIO::TuioTime::getSessionTime());
                gCursorMap[info.pointerId] = gTuioServer->addTuioCursor(
                    xPos,
                    yPos
                );
                gTuioServer->commitFrame();
#endif
            }
            else if (info.pointerFlags & POINTER_FLAG_UPDATE) {
                // Handle update of touchpoint
#ifdef ENABLE_DIRECTMSG
                TouchInputHolder* points = gTouchInputsMap[info.pointerId].get();

                if (points->tryAddInput(touchInput)) {
                    global::openSpaceEngine.touchUpdateCallback(points->latestInput());
                }
#endif
#ifdef ENABLE_TUIOMESSAGES
                TUIO::TuioTime frameTime = TUIO::TuioTime::getSessionTime();
                if (gCursorMap[info.pointerId]->getTuioTime() == frameTime) {
                    break;
                }
                gTuioServer->initFrame(frameTime);
                gTuioServer->updateTuioCursor(gCursorMap[info.pointerId], xPos, yPos);
                gTuioServer->commitFrame();
#endif
            }
            else if (info.pointerFlags & POINTER_FLAG_UP) {
#ifdef ENABLE_DIRECTMSG
                gTouchInputsMap.erase(info.pointerId);
                global::openSpaceEngine.touchExitCallback(touchInput);
#endif
#ifdef ENABLE_TUIOMESSAGES
                // Handle removed touchpoint
                gTuioServer->initFrame(TUIO::TuioTime::getSessionTime());
                gTuioServer->removeTuioCursor(gCursorMap[info.pointerId]);
                gTuioServer->commitFrame();
                gCursorMap.erase(info.pointerId);
#endif
            }
            break;
        }
    }

    // Pass the hook along!
    return CallNextHookEx(0, nCode, wParam, lParam);
}

Win32TouchHook::Win32TouchHook(void* nativeWindow) {
    HWND hWnd = reinterpret_cast<HWND>(nativeWindow);
    if (hWnd == nullptr) {
        LINFO("No windowhandle available for touch input.");
        return;
    }

    // HACK: This hack is required as long as our GLFW version is based on the touch
    // branch. There is no convenient way to set a GLFWBool (uint32_t) which sets the
    // state of touch-to-mouseinput interpretation. It happens to be 116 bytes into an
    // internal glfw struct...
    uint32_t* HACKY_PTR = (uint32_t *)GetPropW(hWnd, L"GLFW");
    HACKY_PTR += 116/sizeof(uint32_t);
    *HACKY_PTR = 1;

    // Test for touch:
    int value = GetSystemMetrics(SM_DIGITIZER);
    if ((value & NID_READY) == 0) {
        // Don't bother setting up touch hooks?
        return;
    }
    // stack ready, drivers installed and digitizer is ready for input
    if (value & NID_MULTI_INPUT) {
        // Digitizer is multitouch
        LINFO("Found Multitouch input digitizer!");
    }
    if (value & NID_INTEGRATED_TOUCH) {
        // Integrated touch
    }

    // This should be needed, but we seem to receive messages even without it,
    // this ought to be part to the older (< win8) windows touch-api.
    // Also - RegisterTouchWindow enables Windows gestures, which we don't want
    // since they produce visual feedback for "press-and-tap" etc.
    // RegisterTouchWindow(hWnd, TWF_FINETOUCH | TWF_WANTPALM);

    // TODO: Would be nice to find out if the gesture "press-and-tap" can be disabled
    // basically we don't really care for windows gestures for now...
    // this disables press and hold (right-click) gesture
    const UINT_PTR dwHwndTabletProperty = TABLET_DISABLE_PRESSANDHOLD;

    ATOM atom = ::GlobalAddAtom(MICROSOFT_TABLETPENSERVICE_PROPERTY);
    ::SetProp(
        hWnd,
        MICROSOFT_TABLETPENSERVICE_PROPERTY,
        reinterpret_cast<HANDLE>(dwHwndTabletProperty)
    );
    ::GlobalDeleteAtom(atom);

    if (!gStarted) {
        gStarted = true;
        gStartTime = std::chrono::duration_cast<std::chrono::microseconds>(
            std::chrono::high_resolution_clock::now().time_since_epoch()
        );
#ifdef ENABLE_TUIOMESSAGES
        gTuioServer = new TUIO::TuioServer("localhost", 3333);
        TUIO::TuioTime::initSession();
#endif
        gTouchHook = SetWindowsHookExW(
            WH_GETMESSAGE,
            HookCallback,
            GetModuleHandleW(nullptr),
            GetCurrentThreadId()
        );

        // In theory, if our UI is pumped from a different thread, we can
        // handle Low-level mouse events in that thread as well.
        // this might help reduce mouse lag while running OpenSpace?
        // gMouseHookThread = new std::thread([](){
        //     gMouseHook = SetWindowsHookExW(
        //         WH_MOUSE_LL,
        //         LowLevelMouseProc,
        //         GetModuleHandleW(NULL),
        //         0 //<- Global thread id (low-level mouse is global only)
        //     );
        //     if (!gMouseHook) {
        //         LINFO("Could not setup mousehook!");
        //     }

        //     MSG msg;
        //     while (GetMessage(&msg, NULL, 0, 0)) {
        //         DispatchMessage(&msg);
        //     }
        // });

        if (!gTouchHook) {
            LINFO(fmt::format("Failed to setup WindowsHook for touch input redirection"));
#ifdef ENABLE_TUIOMESSAGES
            delete gTuioServer;
#endif
            gStarted = false;
        }
    }
}

Win32TouchHook::~Win32TouchHook() {
    if (gStarted) {
        UnhookWindowsHookEx(gTouchHook);
        UnhookWindowsHookEx(gMouseHook);
#ifdef ENABLE_TUIOMESSAGES
        delete gTuioServer;
#endif
    }
}

// Low-level mouse hook is "needed" if we want to stop mousecursor from moving
// when we get a touch-input on our window A negative effect is that this
// function is for global threads, meaning our application will cause Windows to
// stall the mouse cursor when this function can't be scheduled. This is not yet
// fail-proof...might be a race-condition on message pumping?
// - Seems to move the cursor when we get two fingers as input..
// - If we ourselves would pump windows for events, we can handle this in the
// pump-loop
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
    constexpr const LONG_PTR SIGNATURE_MASK = 0xFFFFFF00;
    constexpr const LONG_PTR MOUSEEVENTF_FROMTOUCH = 0xFF515700;
    if (nCode < 0) {
        // do not process message
        return CallNextHookEx(0, nCode, wParam, lParam);
    }
    LPMSLLHOOKSTRUCT msg = reinterpret_cast<LPMSLLHOOKSTRUCT>(lParam);
    // block injected events (in most cases generated by touches)
    bool isFromTouch = (msg->dwExtraInfo || SIGNATURE_MASK) == MOUSEEVENTF_FROMTOUCH;
    if (msg->flags & LLMHF_INJECTED || isFromTouch) {
        return 1;
    }

    // forward event
    return CallNextHookEx(0, nCode, wParam, lParam);
}

} // namespace openspace

#endif // WIN32
<|endoftext|>


<commit_before>// Copyright (c) 2009 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/tools/flip_server/spdy_ssl.h"

#include "base/logging.h"
#include "openssl/err.h"
#include "openssl/ssl.h"

namespace net {

#define NEXT_PROTO_STRING "\x06spdy/2\x08http/1.1\x08http/1.0"
#define SSL_CIPHER_LIST "!aNULL:!ADH:!eNull:!LOW:!EXP:RC4+RSA:MEDIUM:HIGH"

int ssl_set_npn_callback(SSL *s,
                         const unsigned char **data,
                         unsigned int *len,
                         void *arg) {
  VLOG(1) <<  "SSL NPN callback: advertising protocols.";
  *data = (const unsigned char *) NEXT_PROTO_STRING;
  *len = strlen(NEXT_PROTO_STRING);
  return SSL_TLSEXT_ERR_OK;
}

void InitSSL(SSLState* state,
             std::string ssl_cert_name,
             std::string ssl_key_name,
             bool use_npn,
             int session_expiration_time,
             bool disable_ssl_compression) {
  SSL_library_init();
  PrintSslError();

  SSL_load_error_strings();
  PrintSslError();

  state->ssl_method = SSLv23_method();
  state->ssl_ctx = SSL_CTX_new(state->ssl_method);
  if (!state->ssl_ctx) {
    PrintSslError();
    LOG(FATAL) << "Unable to create SSL context";
  }
  // Disable SSLv2 support.
  SSL_CTX_set_options(state->ssl_ctx,
                      SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE);
  if (SSL_CTX_use_certificate_file(state->ssl_ctx,
                                   ssl_cert_name.c_str(),
                                   SSL_FILETYPE_PEM) <= 0) {
    PrintSslError();
    LOG(FATAL) << "Unable to use cert.pem as SSL cert.";
  }
  if (SSL_CTX_use_PrivateKey_file(state->ssl_ctx,
                                  ssl_key_name.c_str(),
                                  SSL_FILETYPE_PEM) <= 0) {
    PrintSslError();
    LOG(FATAL) << "Unable to use key.pem as SSL key.";
  }
  if (!SSL_CTX_check_private_key(state->ssl_ctx)) {
    PrintSslError();
    LOG(FATAL) << "The cert.pem and key.pem files don't match";
  }
  if (use_npn) {
    SSL_CTX_set_next_protos_advertised_cb(state->ssl_ctx,
                                          ssl_set_npn_callback, NULL);
  }
  VLOG(1) << "SSL CTX default cipher list: " << SSL_CIPHER_LIST;
  SSL_CTX_set_cipher_list(state->ssl_ctx, SSL_CIPHER_LIST);

  VLOG(1) << "SSL CTX session expiry: " << session_expiration_time
          << " seconds";
  SSL_CTX_set_timeout(state->ssl_ctx, session_expiration_time);

#ifdef SSL_MODE_RELEASE_BUFFERS
  VLOG(1) << "SSL CTX: Setting Release Buffers mode.";
  SSL_CTX_set_mode(state->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
#endif

  // Proper methods to disable compression don't exist until 0.9.9+. For now
  // we must manipulate the stack of compression methods directly.
  if (disable_ssl_compression) {
    STACK_OF(SSL_COMP) *ssl_comp_methods = SSL_COMP_get_compression_methods();
    int num_methods = sk_SSL_COMP_num(ssl_comp_methods);
    int i;
    for (i = 0; i < num_methods; i++) {
      static_cast<void>(sk_SSL_COMP_delete(ssl_comp_methods, i));
    }
  }
}

SSL* CreateSSLContext(SSL_CTX* ssl_ctx) {
  SSL* ssl = SSL_new(ssl_ctx);
  SSL_set_accept_state(ssl);
  PrintSslError();
  return ssl;
}

void PrintSslError() {
  char buf[128];  // this buffer must be at least 120 chars long.
  int error_num = ERR_get_error();
  while (error_num != 0) {
    ERR_error_string_n(error_num, buf, sizeof(buf));
    LOG(ERROR) << buf;
    error_num = ERR_get_error();
  }
}

}  // namespace net

<commit_msg>Support loading of chained certificates from the cert file.<commit_after>// Copyright (c) 2009 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/tools/flip_server/spdy_ssl.h"

#include "base/logging.h"
#include "openssl/err.h"
#include "openssl/ssl.h"

namespace net {

#define NEXT_PROTO_STRING "\x06spdy/2\x08http/1.1\x08http/1.0"
#define SSL_CIPHER_LIST "!aNULL:!ADH:!eNull:!LOW:!EXP:RC4+RSA:MEDIUM:HIGH"

int ssl_set_npn_callback(SSL *s,
                         const unsigned char **data,
                         unsigned int *len,
                         void *arg) {
  VLOG(1) <<  "SSL NPN callback: advertising protocols.";
  *data = (const unsigned char *) NEXT_PROTO_STRING;
  *len = strlen(NEXT_PROTO_STRING);
  return SSL_TLSEXT_ERR_OK;
}

void InitSSL(SSLState* state,
             std::string ssl_cert_name,
             std::string ssl_key_name,
             bool use_npn,
             int session_expiration_time,
             bool disable_ssl_compression) {
  SSL_library_init();
  PrintSslError();

  SSL_load_error_strings();
  PrintSslError();

  state->ssl_method = SSLv23_method();
  state->ssl_ctx = SSL_CTX_new(state->ssl_method);
  if (!state->ssl_ctx) {
    PrintSslError();
    LOG(FATAL) << "Unable to create SSL context";
  }
  // Disable SSLv2 support.
  SSL_CTX_set_options(state->ssl_ctx,
                      SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE);
  if (SSL_CTX_use_certificate_chain_file(state->ssl_ctx,
                                         ssl_cert_name.c_str()) <= 0) {
    PrintSslError();
    LOG(FATAL) << "Unable to use cert.pem as SSL cert.";
  }
  if (SSL_CTX_use_PrivateKey_file(state->ssl_ctx,
                                  ssl_key_name.c_str(),
                                  SSL_FILETYPE_PEM) <= 0) {
    PrintSslError();
    LOG(FATAL) << "Unable to use key.pem as SSL key.";
  }
  if (!SSL_CTX_check_private_key(state->ssl_ctx)) {
    PrintSslError();
    LOG(FATAL) << "The cert.pem and key.pem files don't match";
  }
  if (use_npn) {
    SSL_CTX_set_next_protos_advertised_cb(state->ssl_ctx,
                                          ssl_set_npn_callback, NULL);
  }
  VLOG(1) << "SSL CTX default cipher list: " << SSL_CIPHER_LIST;
  SSL_CTX_set_cipher_list(state->ssl_ctx, SSL_CIPHER_LIST);

  VLOG(1) << "SSL CTX session expiry: " << session_expiration_time
          << " seconds";
  SSL_CTX_set_timeout(state->ssl_ctx, session_expiration_time);

#ifdef SSL_MODE_RELEASE_BUFFERS
  VLOG(1) << "SSL CTX: Setting Release Buffers mode.";
  SSL_CTX_set_mode(state->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
#endif

  // Proper methods to disable compression don't exist until 0.9.9+. For now
  // we must manipulate the stack of compression methods directly.
  if (disable_ssl_compression) {
    STACK_OF(SSL_COMP) *ssl_comp_methods = SSL_COMP_get_compression_methods();
    int num_methods = sk_SSL_COMP_num(ssl_comp_methods);
    int i;
    for (i = 0; i < num_methods; i++) {
      static_cast<void>(sk_SSL_COMP_delete(ssl_comp_methods, i));
    }
  }
}

SSL* CreateSSLContext(SSL_CTX* ssl_ctx) {
  SSL* ssl = SSL_new(ssl_ctx);
  SSL_set_accept_state(ssl);
  PrintSslError();
  return ssl;
}

void PrintSslError() {
  char buf[128];  // this buffer must be at least 120 chars long.
  int error_num = ERR_get_error();
  while (error_num != 0) {
    ERR_error_string_n(error_num, buf, sizeof(buf));
    LOG(ERROR) << buf;
    error_num = ERR_get_error();
  }
}

}  // namespace net

<|endoftext|>


<commit_before>#ifndef _C4_YML_EMIT_HPP_
#define _C4_YML_EMIT_HPP_

#ifndef _C4_YML_WRITER_HPP_
#include "./writer.hpp"
#endif

#ifndef _C4_YML_TREE_HPP_
#include "./tree.hpp"
#endif

#ifndef _C4_YML_NODE_HPP_
#include "./node.hpp"
#endif

namespace c4 {
namespace yml {

template<class Writer> class Emitter;

template<class OStream>
using EmitterOStream = Emitter<WriterOStream<OStream>>;
using EmitterFile = Emitter<WriterFile>;
using EmitterBuf  = Emitter<WriterBuf>;

typedef enum {
    YAML = 0,
    JSON = 1
} EmitType_e;

/** mark a tree or node to be emitted as json */
struct as_json
{
    Tree const* tree;
    size_t node;
    as_json(Tree const& t) : tree(&t), node(t.root_id()) {}
    as_json(Tree const& t, size_t id) : tree(&t), node(id) {}
    as_json(NodeRef const& n) : tree(n.tree()), node(n.id()) {}
};

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

template<class Writer>
class Emitter : public Writer
{
public:

    using Writer::Writer;

    /** emit!
     *
     * When writing to a buffer, returns a substr of the emitted YAML.
     * If the given buffer has insufficient space, the returned span will
     * be null and its size will be the needed space. No writes are done
     * after the end of the buffer.
     *
     * When writing to a file, the returned substr will be null, but its
     * length will be set to the number of bytes written. */
    substr emit(EmitType_e type, Tree const& t, size_t id, bool error_on_excess);
    /** @overload */
    substr emit(EmitType_e type, Tree const& t, bool error_on_excess=true) { return emit(type, t, t.root_id(), error_on_excess); }
    /** @overload */
    substr emit(EmitType_e type, NodeRef const& n, bool error_on_excess=true) { return emit(type, *n.tree(), n.id(), error_on_excess); }

private:

    void _do_visit(Tree const& t, size_t id, size_t ilevel=0, size_t do_indent=1);
    void _do_visit_json(Tree const& t, size_t id);

private:

    void _write(NodeScalar const& sc, NodeType flags, size_t level);
    void _write_json(NodeScalar const& sc, NodeType flags);

    void _write_scalar(csubstr s, bool was_quoted);
    void _write_scalar_json(csubstr s, bool as_key, bool was_quoted);
    void _write_scalar_block(csubstr s, size_t level, bool as_key);

    void _indent(size_t ilevel)
    {
        this->Writer::_do_write(indent_to(ilevel));
    }

    enum {
        _keysc =  (KEY|KEYREF|KEYANCH|KEYQUO)  | ~(VAL|VALREF|VALANCH|VALQUO),
        _valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO)  |  (VAL|VALREF|VALANCH|VALQUO),
        _keysc_json =  (KEY)  | ~(VAL),
        _valsc_json = ~(KEY)  |  (VAL),
    };

    C4_ALWAYS_INLINE void _writek(Tree const& t, size_t id, size_t level) { _write(t.keysc(id), t._p(id)->m_type.type & ~(VAL|VALREF|VALANCH|VALQUO), level); }
    C4_ALWAYS_INLINE void _writev(Tree const& t, size_t id, size_t level) { _write(t.valsc(id), t._p(id)->m_type.type & ~(KEY|KEYREF|KEYANCH|KEYQUO), level); }

    C4_ALWAYS_INLINE void _writek_json(Tree const& t, size_t id) { _write_json(t.keysc(id), t._p(id)->m_type.type & ~(VAL)); }
    C4_ALWAYS_INLINE void _writev_json(Tree const& t, size_t id) { _write_json(t.valsc(id), t._p(id)->m_type.type & ~(KEY)); }
};

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

/** emit YAML to the given file. A null file defaults to stdout.
 * Return the number of bytes written. */
inline size_t emit(Tree const& t, size_t id, FILE *f)
{
    EmitterFile em(f);
    size_t len = em.emit(YAML, t, id, /*error_on_excess*/true).len;
    return len;
}
/** emit JSON to the given file. A null file defaults to stdout.
 * Return the number of bytes written. */
inline size_t emit_json(Tree const& t, size_t id, FILE *f)
{
    EmitterFile em(f);
    size_t len = em.emit(JSON, t, id, /*error_on_excess*/true).len;
    return len;
}

/** emit YAML to the given file. A null file defaults to stdout.
 * Return the number of bytes written.
 * @overload */
inline size_t emit(Tree const& t, FILE *f=nullptr)
{
    return emit(t, t.root_id(), f);
}
/** emit JSON to the given file. A null file defaults to stdout.
 * Return the number of bytes written.
 * @overload */
inline size_t emit_json(Tree const& t, FILE *f=nullptr)
{
    return emit_json(t, t.root_id(), f);
}

/** emit YAML to the given file. A null file defaults to stdout.
 * Return the number of bytes written.
 * @overload */
inline size_t emit(NodeRef const& r, FILE *f=nullptr)
{
    return emit(*r.tree(), r.id(), f);
}
/** emit JSON to the given file. A null file defaults to stdout.
 * Return the number of bytes written.
 * @overload */
inline size_t emit_json(NodeRef const& r, FILE *f=nullptr)
{
    return emit_json(*r.tree(), r.id(), f);
}

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

/** emit YAML to an STL-like ostream */
template<class OStream>
inline OStream& operator<< (OStream& s, Tree const& t)
{
    EmitterOStream<OStream> em(s);
    em.emit(YAML, t.rootref());
    return s;
}

/** emit YAML to an STL-like ostream
 * @overload */
template<class OStream>
inline OStream& operator<< (OStream& s, NodeRef const& n)
{
    EmitterOStream<OStream> em(s);
    em.emit(YAML, n);
    return s;
}

/** emit json to the stream */
template<class OStream>
inline OStream& operator<< (OStream& s, as_json const& js)
{
    EmitterOStream<OStream> em(s);
    em.emit(JSON, *js.tree, js.node);
    return s;
}

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

/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload */
inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
{
    EmitterBuf em(buf);
    substr result = em.emit(YAML, t, id, error_on_excess);
    return result;
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload */
inline substr emit_json(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
{
    EmitterBuf em(buf);
    substr result = em.emit(JSON, t, id, error_on_excess);
    return result;
}

/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload */
inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
{
    return emit(t, t.root_id(), buf, error_on_excess);
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload */
inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
{
    return emit_json(t, t.root_id(), buf, error_on_excess);
}

/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload
 */
inline substr emit(NodeRef const& r, substr buf, bool error_on_excess=true)
{
    return emit(*r.tree(), r.id(), buf, error_on_excess);
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload
 */
inline substr emit_json(NodeRef const& r, substr buf, bool error_on_excess=true)
{
    return emit_json(*r.tree(), r.id(), buf, error_on_excess);
}

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

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)
{
    substr buf = to_substr(*cont);
    substr ret = emit(t, id, buf, /*error_on_excess*/false);
    if(ret.str == nullptr && ret.len > 0)
    {
        cont->resize(ret.len);
        buf = to_substr(*cont);
        ret = emit(t, id, buf, /*error_on_excess*/true);
    }
    return ret;
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
{
    substr buf = to_substr(*cont);
    substr ret = emit_json(t, id, buf, /*error_on_excess*/false);
    if(ret.str == nullptr && ret.len > 0)
    {
        cont->resize(ret.len);
        buf = to_substr(*cont);
        ret = emit_json(t, id, buf, /*error_on_excess*/true);
    }
    return ret;
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs(Tree const& t, size_t id)
{
    CharOwningContainer c;
    emitrs(t, id, &c);
    return c;
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t, size_t id)
{
    CharOwningContainer c;
    emitrs_json(t, id, &c);
    return c;
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs(Tree const& t, CharOwningContainer * cont)
{
    return emitrs(t, t.root_id(), cont);
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, CharOwningContainer * cont)
{
    return emitrs_json(t, t.root_id(), cont);
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs(Tree const& t)
{
    CharOwningContainer c;
    emitrs(t, t.root_id(), &c);
    return c;
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t)
{
    CharOwningContainer c;
    emitrs_json(t, t.root_id(), &c);
    return c;
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs(NodeRef const& n, CharOwningContainer * cont)
{
    return emitrs(*n.tree(), n.id(), cont);
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(NodeRef const& n, CharOwningContainer * cont)
{
    return emitrs_json(*n.tree(), n.id(), cont);
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs(NodeRef const& n)
{
    CharOwningContainer c;
    emitrs(*n.tree(), n.id(), &c);
    return c;
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(NodeRef const& n)
{
    CharOwningContainer c;
    emitrs_json(*n.tree(), n.id(), &c);
    return c;
}

} // namespace yml
} // namespace c4

#include "./emit.def.hpp"

#endif /* _C4_YML_EMIT_HPP_ */
<commit_msg>[fix] emit: fix emitting json to streams<commit_after>#ifndef _C4_YML_EMIT_HPP_
#define _C4_YML_EMIT_HPP_

#ifndef _C4_YML_WRITER_HPP_
#include "./writer.hpp"
#endif

#ifndef _C4_YML_TREE_HPP_
#include "./tree.hpp"
#endif

#ifndef _C4_YML_NODE_HPP_
#include "./node.hpp"
#endif

namespace c4 {
namespace yml {

template<class Writer> class Emitter;

template<class OStream>
using EmitterOStream = Emitter<WriterOStream<OStream>>;
using EmitterFile = Emitter<WriterFile>;
using EmitterBuf  = Emitter<WriterBuf>;

typedef enum {
    YAML = 0,
    JSON = 1
} EmitType_e;

/** mark a tree or node to be emitted as json */
struct as_json
{
    Tree const* tree;
    size_t node;
    as_json(Tree const& t) : tree(&t), node(t.root_id()) {}
    as_json(Tree const& t, size_t id) : tree(&t), node(id) {}
    as_json(NodeRef const& n) : tree(n.tree()), node(n.id()) {}
};

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

template<class Writer>
class Emitter : public Writer
{
public:

    using Writer::Writer;

    /** emit!
     *
     * When writing to a buffer, returns a substr of the emitted YAML.
     * If the given buffer has insufficient space, the returned span will
     * be null and its size will be the needed space. No writes are done
     * after the end of the buffer.
     *
     * When writing to a file, the returned substr will be null, but its
     * length will be set to the number of bytes written. */
    substr emit(EmitType_e type, Tree const& t, size_t id, bool error_on_excess);
    /** @overload */
    substr emit(EmitType_e type, Tree const& t, bool error_on_excess=true) { return emit(type, t, t.root_id(), error_on_excess); }
    /** @overload */
    substr emit(EmitType_e type, NodeRef const& n, bool error_on_excess=true) { return emit(type, *n.tree(), n.id(), error_on_excess); }

private:

    void _do_visit(Tree const& t, size_t id, size_t ilevel=0, size_t do_indent=1);
    void _do_visit_json(Tree const& t, size_t id);

private:

    void _write(NodeScalar const& sc, NodeType flags, size_t level);
    void _write_json(NodeScalar const& sc, NodeType flags);

    void _write_scalar(csubstr s, bool was_quoted);
    void _write_scalar_json(csubstr s, bool as_key, bool was_quoted);
    void _write_scalar_block(csubstr s, size_t level, bool as_key);

    void _indent(size_t ilevel)
    {
        this->Writer::_do_write(indent_to(ilevel));
    }

    enum {
        _keysc =  (KEY|KEYREF|KEYANCH|KEYQUO)  | ~(VAL|VALREF|VALANCH|VALQUO),
        _valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO)  |  (VAL|VALREF|VALANCH|VALQUO),
        _keysc_json =  (KEY)  | ~(VAL),
        _valsc_json = ~(KEY)  |  (VAL),
    };

    C4_ALWAYS_INLINE void _writek(Tree const& t, size_t id, size_t level) { _write(t.keysc(id), t._p(id)->m_type.type & ~(VAL|VALREF|VALANCH|VALQUO), level); }
    C4_ALWAYS_INLINE void _writev(Tree const& t, size_t id, size_t level) { _write(t.valsc(id), t._p(id)->m_type.type & ~(KEY|KEYREF|KEYANCH|KEYQUO), level); }

    C4_ALWAYS_INLINE void _writek_json(Tree const& t, size_t id) { _write_json(t.keysc(id), t._p(id)->m_type.type & ~(VAL)); }
    C4_ALWAYS_INLINE void _writev_json(Tree const& t, size_t id) { _write_json(t.valsc(id), t._p(id)->m_type.type & ~(KEY)); }
};

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

/** emit YAML to the given file. A null file defaults to stdout.
 * Return the number of bytes written. */
inline size_t emit(Tree const& t, size_t id, FILE *f)
{
    EmitterFile em(f);
    size_t len = em.emit(YAML, t, id, /*error_on_excess*/true).len;
    return len;
}
/** emit JSON to the given file. A null file defaults to stdout.
 * Return the number of bytes written. */
inline size_t emit_json(Tree const& t, size_t id, FILE *f)
{
    EmitterFile em(f);
    size_t len = em.emit(JSON, t, id, /*error_on_excess*/true).len;
    return len;
}

/** emit YAML to the given file. A null file defaults to stdout.
 * Return the number of bytes written.
 * @overload */
inline size_t emit(Tree const& t, FILE *f=nullptr)
{
    return emit(t, t.root_id(), f);
}
/** emit JSON to the given file. A null file defaults to stdout.
 * Return the number of bytes written.
 * @overload */
inline size_t emit_json(Tree const& t, FILE *f=nullptr)
{
    return emit_json(t, t.root_id(), f);
}

/** emit YAML to the given file. A null file defaults to stdout.
 * Return the number of bytes written.
 * @overload */
inline size_t emit(NodeRef const& r, FILE *f=nullptr)
{
    return emit(*r.tree(), r.id(), f);
}
/** emit JSON to the given file. A null file defaults to stdout.
 * Return the number of bytes written.
 * @overload */
inline size_t emit_json(NodeRef const& r, FILE *f=nullptr)
{
    return emit_json(*r.tree(), r.id(), f);
}

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

/** emit YAML to an STL-like ostream */
template<class OStream>
inline OStream& operator<< (OStream& s, Tree const& t)
{
    EmitterOStream<OStream> em(s);
    em.emit(YAML, t.rootref());
    return s;
}

/** emit YAML to an STL-like ostream
 * @overload */
template<class OStream>
inline OStream& operator<< (OStream& s, NodeRef const& n)
{
    EmitterOStream<OStream> em(s);
    em.emit(YAML, n);
    return s;
}

/** emit json to the stream */
template<class OStream>
inline OStream& operator<< (OStream& s, as_json const& js)
{
    EmitterOStream<OStream> em(s);
    em.emit(JSON, *js.tree, js.node, true);
    return s;
}

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

/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload */
inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
{
    EmitterBuf em(buf);
    substr result = em.emit(YAML, t, id, error_on_excess);
    return result;
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload */
inline substr emit_json(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
{
    EmitterBuf em(buf);
    substr result = em.emit(JSON, t, id, error_on_excess);
    return result;
}

/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload */
inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
{
    return emit(t, t.root_id(), buf, error_on_excess);
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload */
inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
{
    return emit_json(t, t.root_id(), buf, error_on_excess);
}

/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload
 */
inline substr emit(NodeRef const& r, substr buf, bool error_on_excess=true)
{
    return emit(*r.tree(), r.id(), buf, error_on_excess);
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
 * @overload
 */
inline substr emit_json(NodeRef const& r, substr buf, bool error_on_excess=true)
{
    return emit_json(*r.tree(), r.id(), buf, error_on_excess);
}

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

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)
{
    substr buf = to_substr(*cont);
    substr ret = emit(t, id, buf, /*error_on_excess*/false);
    if(ret.str == nullptr && ret.len > 0)
    {
        cont->resize(ret.len);
        buf = to_substr(*cont);
        ret = emit(t, id, buf, /*error_on_excess*/true);
    }
    return ret;
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
{
    substr buf = to_substr(*cont);
    substr ret = emit_json(t, id, buf, /*error_on_excess*/false);
    if(ret.str == nullptr && ret.len > 0)
    {
        cont->resize(ret.len);
        buf = to_substr(*cont);
        ret = emit_json(t, id, buf, /*error_on_excess*/true);
    }
    return ret;
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs(Tree const& t, size_t id)
{
    CharOwningContainer c;
    emitrs(t, id, &c);
    return c;
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t, size_t id)
{
    CharOwningContainer c;
    emitrs_json(t, id, &c);
    return c;
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs(Tree const& t, CharOwningContainer * cont)
{
    return emitrs(t, t.root_id(), cont);
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, CharOwningContainer * cont)
{
    return emitrs_json(t, t.root_id(), cont);
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs(Tree const& t)
{
    CharOwningContainer c;
    emitrs(t, t.root_id(), &c);
    return c;
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t)
{
    CharOwningContainer c;
    emitrs_json(t, t.root_id(), &c);
    return c;
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs(NodeRef const& n, CharOwningContainer * cont)
{
    return emitrs(*n.tree(), n.id(), cont);
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(NodeRef const& n, CharOwningContainer * cont)
{
    return emitrs_json(*n.tree(), n.id(), cont);
}

/** emit+resize: YAML to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs(NodeRef const& n)
{
    CharOwningContainer c;
    emitrs(*n.tree(), n.id(), &c);
    return c;
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
 * resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(NodeRef const& n)
{
    CharOwningContainer c;
    emitrs_json(*n.tree(), n.id(), &c);
    return c;
}

} // namespace yml
} // namespace c4

#include "./emit.def.hpp"

#endif /* _C4_YML_EMIT_HPP_ */
<|endoftext|>