<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "stdafx.h"

// #define ZORBA_DEBUG_ICU_STREAMBUF
#ifdef ZORBA_DEBUG_ICU_STREAMBUF
# include <stdio.h>
#endif

#include <algorithm>
#include <cassert>
#include <stdexcept>

#include <zorba/config.h>
#include <zorba/diagnostic_list.h>

#include "diagnostics/assert.h"
#include "diagnostics/diagnostic.h"
#include "diagnostics/zorba_exception.h"
#include "util/cxx_util.h"
#include "util/string_util.h"
#include "util/utf8_util.h"

#include "icu_streambuf.h"

using namespace std;

namespace zorba {

int const Small_External_Buf_Size = 6;
int const Large_External_Buf_Size = 4096;

///////////////////////////////////////////////////////////////////////////////

inline void icu_streambuf::buf_type_base::reset() {
  pivot_source_ = pivot_target_ = pivot_buf_;
}

inline void icu_streambuf::resetg() {
  setg(
    g_.utf8_char_, g_.utf8_char_ + sizeof g_.utf8_char_,
    g_.utf8_char_ + sizeof g_.utf8_char_
  );
}

icu_streambuf::icu_streambuf( char const *charset, streambuf *orig ) :
  proxy_streambuf( orig ),
  no_conv_( !is_necessary( charset ) ),
  external_conv_( no_conv_ ? nullptr : create_conv( charset ) ),
  utf8_conv_( no_conv_ ? nullptr : create_conv( "UTF-8" ) )
{
  if ( !orig )
    throw invalid_argument( "null streambuf" );
  resetg();
}

icu_streambuf::~icu_streambuf() {
  if ( external_conv_ )
    ucnv_close( external_conv_ );
  if ( utf8_conv_ )
    ucnv_close( utf8_conv_ );
}

void icu_streambuf::clear() {
  if ( !no_conv_ ) {
    ucnv_reset( external_conv_ );
    ucnv_reset( utf8_conv_ );
    g_.reset();
    p_.reset();
    resetg();
  }
}

UConverter* icu_streambuf::create_conv( char const *charset ) {
  UErrorCode err = U_ZERO_ERROR;
  UConverter *const conv = ucnv_open( charset, &err );
  ucnv_setFromUCallBack(
    conv, UCNV_FROM_U_CALLBACK_STOP, nullptr, nullptr, nullptr, &err
  );
  ucnv_setToUCallBack(
    conv, UCNV_TO_U_CALLBACK_STOP, nullptr, nullptr, nullptr, &err
  );
  if ( !conv || U_FAILURE( err ) ) {
    if ( conv )
      ucnv_close( conv );
    throw invalid_argument( u_errorName( err ) );
  }
  return conv;
}

bool icu_streambuf::is_necessary( char const *cc_charset ) {
  if ( !*cc_charset )
    throw invalid_argument( "empty charset" );
  //
  // Apparently, ucnv_compareNames() doesn't consider "US-ASCII" an alias for
  // "ASCII", so check for "US-ASCII" ourselves.
  //
  zstring charset( cc_charset );
  ascii::trim_whitespace( charset );
  ascii::to_upper( charset );
  if ( charset == "US-ASCII" )
    cc_charset += 3; // skip "US-"

  return  ucnv_compareNames( cc_charset, "ASCII" )
      &&  ucnv_compareNames( cc_charset, "UTF-8" );
}

bool icu_streambuf::is_supported( char const *charset ) {
  try {
    ucnv_close( create_conv( charset ) );
    return true;
  }
  catch ( invalid_argument const& ) {
    return false;
  }
}

icu_streambuf::pos_type icu_streambuf::seekoff( off_type o, ios_base::seekdir d,
                                                ios_base::openmode m ) {
  clear();
  return original()->pubseekoff( o, d, m );
}

icu_streambuf::pos_type icu_streambuf::seekpos( pos_type p,
                                                ios_base::openmode m ) {
  clear();
  return original()->pubseekpos( p, m );
}

streambuf* icu_streambuf::setbuf( char_type *p, streamsize s ) {
  original()->pubsetbuf( p, s );
  return this;
}

int icu_streambuf::sync() {
  return original()->pubsync();
}

icu_streambuf::int_type icu_streambuf::overflow( int_type c ) {
#if ZORBA_DEBUG_ICU_STREAMBUF
  printf( "overflow()\n" );
#endif
  if ( no_conv_ )
    return original()->sputc( c );

  if ( traits_type::eq_int_type( c, traits_type::eof() ) )
    return traits_type::eof();

  char_type const utf8_byte = traits_type::to_char_type( c );
  char_type const *from = &utf8_byte;
  char ebuf[ Small_External_Buf_Size ], *to = ebuf;

#ifdef NDEBUG
  to_external( &from, from + 1, &to, to + sizeof ebuf );
#else
  bool const ok = to_external( &from, from + 1, &to, to + sizeof ebuf );
  assert( ok );
#endif /* NDEBUG */
  if ( streamsize const n = to - ebuf ) {
    original()->sputn( ebuf, n );
    p_.reset();
  }

  return c;
}

#ifdef __GNUC__
# ifdef GCC_PRAGMA_DIAGNOSTIC_PUSH
#   pragma GCC diagnostic push
# endif /* GCC_PRAGMA_DIAGNOSTIC_PUSH */
//
// Disables warnings about p.pivot_buf_ + sizeof p.pivot_buf_.
//
# pragma GCC diagnostic ignored "-Warray-bounds"
#endif /* __GNUC__ */

bool icu_streambuf::to_external( char_type const **from,
                                 char_type const *from_end, char **to,
                                 char const *to_end, bool flush ) {
  UErrorCode err = U_ZERO_ERROR;
  ucnv_convertEx(
    external_conv_, utf8_conv_, to, to_end, from, from_end,
    p_.pivot_buf_, &p_.pivot_source_, &p_.pivot_target_,
    p_.pivot_buf_ + sizeof p_.pivot_buf_,
    /*reset*/ false, flush, &err
  );
  if ( err == U_TRUNCATED_CHAR_FOUND || err == U_BUFFER_OVERFLOW_ERROR )
    return false;
  if ( U_FAILURE( err ) )
    throw ZORBA_EXCEPTION(
      zerr::ZOSE0006_TRANSCODING_ERROR, ERROR_PARAMS( u_errorName( err ) )
    );
  return true;
}

bool icu_streambuf::to_utf8( char const **from, char const *from_end,
                             char_type **to, char_type const *to_end,
                             bool flush ) {
  UErrorCode err = U_ZERO_ERROR;
  ucnv_convertEx(
    utf8_conv_, external_conv_, to, to_end, from, from_end,
    g_.pivot_buf_, &g_.pivot_source_, &g_.pivot_target_,
    g_.pivot_buf_ + sizeof g_.pivot_buf_,
    /*reset*/ false, flush, &err
  );
  if ( err == U_TRUNCATED_CHAR_FOUND || err == U_BUFFER_OVERFLOW_ERROR )
    return false;
  if ( U_FAILURE( err ) )
    throw ZORBA_EXCEPTION(
      zerr::ZOSE0006_TRANSCODING_ERROR, ERROR_PARAMS( u_errorName( err ) )
    );
  return true;
}

#ifdef GCC_PRAGMA_DIAGNOSTIC_PUSH
# pragma GCC diagnostic pop
#else
# pragma GCC diagnostic warning "-Warray-bounds"
#endif /* GCC_PRAGMA_DIAGNOSTIC_PUSH */

icu_streambuf::int_type icu_streambuf::underflow() {
#if ZORBA_DEBUG_ICU_STREAMBUF
  printf( "underflow()\n" );
#endif
  if ( no_conv_ )
    return original()->sgetc();

  if ( gptr() >= egptr() ) {
    utf8::storage_type *to = g_.utf8_char_;
    utf8::storage_type const *const to_end = to + sizeof g_.utf8_char_;

    while ( true ) {
      int_type const c = original()->sbumpc();
      if ( traits_type::eq_int_type( c, traits_type::eof() ) )
        return traits_type::eof();

      char const ebyte = traits_type::to_char_type( c );
      char const *from = &ebyte;

      to_utf8( &from, from + 1, &to, to_end );
      if ( to > g_.utf8_char_ ) {
        setg( g_.utf8_char_, g_.utf8_char_, to );
        g_.reset();
        break;
      }
    }
  }
  return traits_type::to_int_type( *gptr() );
}

streamsize icu_streambuf::xsgetn( char_type *to, streamsize size ) {
#if ZORBA_DEBUG_ICU_STREAMBUF
  printf( "xsgetn()\n" );
#endif
  if ( no_conv_ )
    return original()->sgetn( to, size );

  streamsize return_size = 0;
  char_type *const to_end = to + size;

  if ( streamsize const gsize = egptr() - gptr() ) {
    // must first get any chars in g_.utf8_char_
    streamsize const n = min( gsize, size );
    traits_type::copy( to, gptr(), n );
    gbump( n );
    to += n;
    size -= n, return_size += n;
  }

  while ( size > 0 ) {
    char ebuf[ Large_External_Buf_Size ];
    streamsize const get = min( (streamsize)(sizeof ebuf), size );
    if ( streamsize const got = original()->sgetn( ebuf, get ) ) {
      char const *from = ebuf;
      char_type const *const to_orig = to;
      int_type const peek = original()->sgetc();
      bool const flush = traits_type::eq_int_type( peek, traits_type::eof() );
      to_utf8( &from, from + got, &to, to_end, flush );
      streamsize const n = to - to_orig;
      size -= n, return_size += n;
      if ( flush )
        break;
    } else
      break;
  }
  return return_size;
}

streamsize icu_streambuf::xsputn( char_type const *from, streamsize size ) {
#if ZORBA_DEBUG_ICU_STREAMBUF
  printf( "xsputn()\n" );
#endif
  if ( no_conv_ )
    return original()->sputn( from, size );

  streamsize return_size = 0;
  char_type const *const from_end = from + size;
  char ebuf[ Large_External_Buf_Size ], *to = ebuf;
  char const *const to_end = to + sizeof ebuf;

  while ( size > 0 ) {
    char_type const *const from_orig = from;
    to_external( &from, from_end, &to, to_end );
    streamsize n = to - ebuf;
    if ( n && !original()->sputn( ebuf, n ) )
      break;
    to = ebuf;
    n = from - from_orig;
    size -= n, return_size += n;
  }
  return return_size;
}

///////////////////////////////////////////////////////////////////////////////

} // namespace zorba
/* vim:set et sw=2 ts=2: */
<commit_msg>s/#if/#ifdef/<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "stdafx.h"

// #define ZORBA_DEBUG_ICU_STREAMBUF
#ifdef ZORBA_DEBUG_ICU_STREAMBUF
# include <stdio.h>
#endif

#include <algorithm>
#include <cassert>
#include <stdexcept>

#include <zorba/config.h>
#include <zorba/diagnostic_list.h>

#include "diagnostics/assert.h"
#include "diagnostics/diagnostic.h"
#include "diagnostics/zorba_exception.h"
#include "util/cxx_util.h"
#include "util/string_util.h"
#include "util/utf8_util.h"

#include "icu_streambuf.h"

using namespace std;

namespace zorba {

int const Small_External_Buf_Size = 6;
int const Large_External_Buf_Size = 4096;

///////////////////////////////////////////////////////////////////////////////

inline void icu_streambuf::buf_type_base::reset() {
  pivot_source_ = pivot_target_ = pivot_buf_;
}

inline void icu_streambuf::resetg() {
  setg(
    g_.utf8_char_, g_.utf8_char_ + sizeof g_.utf8_char_,
    g_.utf8_char_ + sizeof g_.utf8_char_
  );
}

icu_streambuf::icu_streambuf( char const *charset, streambuf *orig ) :
  proxy_streambuf( orig ),
  no_conv_( !is_necessary( charset ) ),
  external_conv_( no_conv_ ? nullptr : create_conv( charset ) ),
  utf8_conv_( no_conv_ ? nullptr : create_conv( "UTF-8" ) )
{
  if ( !orig )
    throw invalid_argument( "null streambuf" );
  resetg();
}

icu_streambuf::~icu_streambuf() {
  if ( external_conv_ )
    ucnv_close( external_conv_ );
  if ( utf8_conv_ )
    ucnv_close( utf8_conv_ );
}

void icu_streambuf::clear() {
  if ( !no_conv_ ) {
    ucnv_reset( external_conv_ );
    ucnv_reset( utf8_conv_ );
    g_.reset();
    p_.reset();
    resetg();
  }
}

UConverter* icu_streambuf::create_conv( char const *charset ) {
  UErrorCode err = U_ZERO_ERROR;
  UConverter *const conv = ucnv_open( charset, &err );
  ucnv_setFromUCallBack(
    conv, UCNV_FROM_U_CALLBACK_STOP, nullptr, nullptr, nullptr, &err
  );
  ucnv_setToUCallBack(
    conv, UCNV_TO_U_CALLBACK_STOP, nullptr, nullptr, nullptr, &err
  );
  if ( !conv || U_FAILURE( err ) ) {
    if ( conv )
      ucnv_close( conv );
    throw invalid_argument( u_errorName( err ) );
  }
  return conv;
}

bool icu_streambuf::is_necessary( char const *cc_charset ) {
  if ( !*cc_charset )
    throw invalid_argument( "empty charset" );
  //
  // Apparently, ucnv_compareNames() doesn't consider "US-ASCII" an alias for
  // "ASCII", so check for "US-ASCII" ourselves.
  //
  zstring charset( cc_charset );
  ascii::trim_whitespace( charset );
  ascii::to_upper( charset );
  if ( charset == "US-ASCII" )
    cc_charset += 3; // skip "US-"

  return  ucnv_compareNames( cc_charset, "ASCII" )
      &&  ucnv_compareNames( cc_charset, "UTF-8" );
}

bool icu_streambuf::is_supported( char const *charset ) {
  try {
    ucnv_close( create_conv( charset ) );
    return true;
  }
  catch ( invalid_argument const& ) {
    return false;
  }
}

icu_streambuf::pos_type icu_streambuf::seekoff( off_type o, ios_base::seekdir d,
                                                ios_base::openmode m ) {
  clear();
  return original()->pubseekoff( o, d, m );
}

icu_streambuf::pos_type icu_streambuf::seekpos( pos_type p,
                                                ios_base::openmode m ) {
  clear();
  return original()->pubseekpos( p, m );
}

streambuf* icu_streambuf::setbuf( char_type *p, streamsize s ) {
  original()->pubsetbuf( p, s );
  return this;
}

int icu_streambuf::sync() {
  return original()->pubsync();
}

icu_streambuf::int_type icu_streambuf::overflow( int_type c ) {
#ifdef ZORBA_DEBUG_ICU_STREAMBUF
  printf( "overflow()\n" );
#endif
  if ( no_conv_ )
    return original()->sputc( c );

  if ( traits_type::eq_int_type( c, traits_type::eof() ) )
    return traits_type::eof();

  char_type const utf8_byte = traits_type::to_char_type( c );
  char_type const *from = &utf8_byte;
  char ebuf[ Small_External_Buf_Size ], *to = ebuf;

#ifdef NDEBUG
  to_external( &from, from + 1, &to, to + sizeof ebuf );
#else
  bool const ok = to_external( &from, from + 1, &to, to + sizeof ebuf );
  assert( ok );
#endif /* NDEBUG */
  if ( streamsize const n = to - ebuf ) {
    original()->sputn( ebuf, n );
    p_.reset();
  }

  return c;
}

#ifdef __GNUC__
# ifdef GCC_PRAGMA_DIAGNOSTIC_PUSH
#   pragma GCC diagnostic push
# endif /* GCC_PRAGMA_DIAGNOSTIC_PUSH */
//
// Disables warnings about p.pivot_buf_ + sizeof p.pivot_buf_.
//
# pragma GCC diagnostic ignored "-Warray-bounds"
#endif /* __GNUC__ */

bool icu_streambuf::to_external( char_type const **from,
                                 char_type const *from_end, char **to,
                                 char const *to_end, bool flush ) {
  UErrorCode err = U_ZERO_ERROR;
  ucnv_convertEx(
    external_conv_, utf8_conv_, to, to_end, from, from_end,
    p_.pivot_buf_, &p_.pivot_source_, &p_.pivot_target_,
    p_.pivot_buf_ + sizeof p_.pivot_buf_,
    /*reset*/ false, flush, &err
  );
  if ( err == U_TRUNCATED_CHAR_FOUND || err == U_BUFFER_OVERFLOW_ERROR )
    return false;
  if ( U_FAILURE( err ) )
    throw ZORBA_EXCEPTION(
      zerr::ZOSE0006_TRANSCODING_ERROR, ERROR_PARAMS( u_errorName( err ) )
    );
  return true;
}

bool icu_streambuf::to_utf8( char const **from, char const *from_end,
                             char_type **to, char_type const *to_end,
                             bool flush ) {
  UErrorCode err = U_ZERO_ERROR;
  ucnv_convertEx(
    utf8_conv_, external_conv_, to, to_end, from, from_end,
    g_.pivot_buf_, &g_.pivot_source_, &g_.pivot_target_,
    g_.pivot_buf_ + sizeof g_.pivot_buf_,
    /*reset*/ false, flush, &err
  );
  if ( err == U_TRUNCATED_CHAR_FOUND || err == U_BUFFER_OVERFLOW_ERROR )
    return false;
  if ( U_FAILURE( err ) )
    throw ZORBA_EXCEPTION(
      zerr::ZOSE0006_TRANSCODING_ERROR, ERROR_PARAMS( u_errorName( err ) )
    );
  return true;
}

#ifdef GCC_PRAGMA_DIAGNOSTIC_PUSH
# pragma GCC diagnostic pop
#else
# pragma GCC diagnostic warning "-Warray-bounds"
#endif /* GCC_PRAGMA_DIAGNOSTIC_PUSH */

icu_streambuf::int_type icu_streambuf::underflow() {
#ifdef ZORBA_DEBUG_ICU_STREAMBUF
  printf( "underflow()\n" );
#endif
  if ( no_conv_ )
    return original()->sgetc();

  if ( gptr() >= egptr() ) {
    utf8::storage_type *to = g_.utf8_char_;
    utf8::storage_type const *const to_end = to + sizeof g_.utf8_char_;

    while ( true ) {
      int_type const c = original()->sbumpc();
      if ( traits_type::eq_int_type( c, traits_type::eof() ) )
        return traits_type::eof();

      char const ebyte = traits_type::to_char_type( c );
      char const *from = &ebyte;

      to_utf8( &from, from + 1, &to, to_end );
      if ( to > g_.utf8_char_ ) {
        setg( g_.utf8_char_, g_.utf8_char_, to );
        g_.reset();
        break;
      }
    }
  }
  return traits_type::to_int_type( *gptr() );
}

streamsize icu_streambuf::xsgetn( char_type *to, streamsize size ) {
#ifdef ZORBA_DEBUG_ICU_STREAMBUF
  printf( "xsgetn()\n" );
#endif
  if ( no_conv_ )
    return original()->sgetn( to, size );

  streamsize return_size = 0;
  char_type *const to_end = to + size;

  if ( streamsize const gsize = egptr() - gptr() ) {
    // must first get any chars in g_.utf8_char_
    streamsize const n = min( gsize, size );
    traits_type::copy( to, gptr(), n );
    gbump( n );
    to += n;
    size -= n, return_size += n;
  }

  while ( size > 0 ) {
    char ebuf[ Large_External_Buf_Size ];
    streamsize const get = min( (streamsize)(sizeof ebuf), size );
    if ( streamsize const got = original()->sgetn( ebuf, get ) ) {
      char const *from = ebuf;
      char_type const *const to_orig = to;
      int_type const peek = original()->sgetc();
      bool const flush = traits_type::eq_int_type( peek, traits_type::eof() );
      to_utf8( &from, from + got, &to, to_end, flush );
      streamsize const n = to - to_orig;
      size -= n, return_size += n;
      if ( flush )
        break;
    } else
      break;
  }
  return return_size;
}

streamsize icu_streambuf::xsputn( char_type const *from, streamsize size ) {
#ifdef ZORBA_DEBUG_ICU_STREAMBUF
  printf( "xsputn()\n" );
#endif
  if ( no_conv_ )
    return original()->sputn( from, size );

  streamsize return_size = 0;
  char_type const *const from_end = from + size;
  char ebuf[ Large_External_Buf_Size ], *to = ebuf;
  char const *const to_end = to + sizeof ebuf;

  while ( size > 0 ) {
    char_type const *const from_orig = from;
    to_external( &from, from_end, &to, to_end );
    streamsize n = to - ebuf;
    if ( n && !original()->sputn( ebuf, n ) )
      break;
    to = ebuf;
    n = from - from_orig;
    size -= n, return_size += n;
  }
  return return_size;
}

///////////////////////////////////////////////////////////////////////////////

} // namespace zorba
/* vim:set et sw=2 ts=2: */
<|endoftext|>


<commit_before>#include <Carbon/Carbon.h>
#include "SkApplication.h"
#include "SkWindow.h"

int main(int argc, char* argv[])
{
    WindowRef			window;
    OSStatus			err = noErr;

    Rect bounds = {100, 100, 500, 500};
    WindowAttributes attrs = kWindowStandardHandlerAttribute |
                             kWindowLiveResizeAttribute |
                             kWindowInWindowMenuAttribute |
                             kWindowCompositingAttribute |
                             kWindowAsyncDragAttribute |
                             kWindowFullZoomAttribute |
                             kWindowFrameworkScaledAttribute;
                             //kWindowDoesNotCycleAttribute;
    CreateNewWindow(kDocumentWindowClass, attrs, &bounds, &window);

    MenuRef menu;
    CreateNewMenu(0, 0, &menu);

    // if we get here, we can start our normal Skia sequence
    {
        application_init();
        (void)create_sk_window(window, argc, argv);
        SizeWindow(window, 640, 480, false);
    }

    // The window was created hidden so show it.
    ShowWindow( window );

    // Call the event loop
    RunApplicationEventLoop();

	application_term();

CantCreateWindow:
CantGetNibRef:
	return err;
}

<commit_msg>make the mac window resizeable again<commit_after>#include <Carbon/Carbon.h>
#include "SkApplication.h"
#include "SkWindow.h"

int main(int argc, char* argv[])
{
    WindowRef			window;
    OSStatus			err = noErr;

    Rect bounds = {100, 100, 500, 500};
    WindowAttributes attrs = kWindowStandardHandlerAttribute |
                             kWindowResizableAttribute |
                             kWindowLiveResizeAttribute |
                             kWindowInWindowMenuAttribute |
                             kWindowCompositingAttribute |
                             kWindowAsyncDragAttribute |
                             kWindowFullZoomAttribute |
                             kWindowFrameworkScaledAttribute;
                             //kWindowDoesNotCycleAttribute;
    CreateNewWindow(kDocumentWindowClass, attrs, &bounds, &window);

    MenuRef menu;
    CreateNewMenu(0, 0, &menu);

    // if we get here, we can start our normal Skia sequence
    {
        application_init();
        (void)create_sk_window(window, argc, argv);
        SizeWindow(window, 640, 480, false);
    }

    // The window was created hidden so show it.
    ShowWindow( window );

    // Call the event loop
    RunApplicationEventLoop();

	application_term();

CantCreateWindow:
CantGetNibRef:
	return err;
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2009, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/utp_stream.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/utp_socket_manager.hpp"
#include "libtorrent/instantiate_connection.hpp"
#include "libtorrent/socket_io.hpp"

// #define TORRENT_DEBUG_MTU 1135

namespace libtorrent
{

	utp_socket_manager::utp_socket_manager(session_settings const& sett, udp_socket& s
		, incoming_utp_callback_t cb)
		: m_sock(s)
		, m_cb(cb)
		, m_last_socket(0)
		, m_new_connection(-1)
		, m_sett(sett)
	{}

	utp_socket_manager::~utp_socket_manager()
	{
		for (socket_map_t::iterator i = m_utp_sockets.begin()
			, end(m_utp_sockets.end()); i != end; ++i)
		{
			delete_utp_impl(i->second);
		}
	}

	void utp_socket_manager::get_status(utp_status& s) const
	{
		s.num_idle = 0;
		s.num_syn_sent = 0;
		s.num_connected = 0;
		s.num_fin_sent = 0;
		s.num_close_wait = 0;

		for (socket_map_t::const_iterator i = m_utp_sockets.begin()
			, end(m_utp_sockets.end()); i != end; ++i)
		{
			int state = utp_socket_state(i->second);
			switch (state)
			{
				case 0: ++s.num_idle; break;
				case 1: ++s.num_syn_sent; break;
				case 2: ++s.num_connected; break;
				case 3: ++s.num_fin_sent; break;
				case 4: ++s.num_close_wait; break;
				case 5: ++s.num_close_wait; break;
			}
		}
	}

	void utp_socket_manager::tick(ptime now)
	{
		for (socket_map_t::iterator i = m_utp_sockets.begin()
			, end(m_utp_sockets.end()); i != end;)
		{
			if (should_delete(i->second))
			{
				delete_utp_impl(i->second);
				if (m_last_socket == i->second) m_last_socket = 0;
				m_utp_sockets.erase(i++);
				continue;
			}
			tick_utp_impl(i->second, now);
			++i;
		}
	}

	void utp_socket_manager::send_packet(udp::endpoint const& ep, char const* p
		, int len, error_code& ec, int flags)
	{
		if (!m_sock.is_open())
		{
			ec = asio::error::operation_aborted;
			return;
		}

#ifdef TORRENT_DEBUG_MTU
		// drop packets that exceed the debug MTU
		if ((flags & dont_fragment) && len > TORRENT_DEBUG_MTU) return;
#endif

#ifdef TORRENT_HAS_DONT_FRAGMENT
		error_code tmp;
		if (flags & dont_fragment) m_sock.set_option(dont_fragment(true), tmp);
#endif
		m_sock.send(ep, p, len, ec);
#ifdef TORRENT_HAS_DONT_FRAGMENT
		if (flags & dont_fragment) m_sock.set_option(dont_fragment(false), tmp);
#endif
	}

	tcp::endpoint utp_socket_manager::local_endpoint(error_code& ec) const
	{
		return m_sock.local_endpoint(ec);
	}

	bool utp_socket_manager::incoming_packet(char const* p, int size, udp::endpoint const& ep)
	{
//		UTP_LOGV("incoming packet size:%d\n", size);

		if (size < sizeof(utp_header)) return false;

		utp_header const* ph = (utp_header*)p;

//		UTP_LOGV("incoming packet version:%d\n", int(ph->get_version()));

		if (ph->get_version() != 1) return false;

		const ptime receive_time = time_now_hires();

		// parse out connection ID and look for existing
		// connections. If found, forward to the utp_stream.
		boost::uint16_t id = ph->connection_id;

		// first test to see if it's the same socket as last time
		// in most cases it is
		if (m_last_socket
			&& utp_match(m_last_socket, ep, id))
		{
			return utp_incoming_packet(m_last_socket, p, size, ep, receive_time);
		}

		socket_map_t::iterator i = m_utp_sockets.find(id);

		std::pair<socket_map_t::iterator, socket_map_t::iterator> r =
			m_utp_sockets.equal_range(id);

		for (; r.first != r.second; ++r.first)
		{
			if (!utp_match(r.first->second, ep, id)) continue;
			bool ret = utp_incoming_packet(r.first->second, p, size, ep, receive_time);
			if (ret) m_last_socket = r.first->second;
			return ret;
		}

//		UTP_LOGV("incoming packet id:%d source:%s\n", id, print_endpoint(ep).c_str());

		if (!m_sett.enable_incoming_utp)
			return false;

		// if not found, see if it's a SYN packet, if it is,
		// create a new utp_stream
		if (ph->get_type() == ST_SYN)
		{
			// create the new socket with this ID
			m_new_connection = id;

//			UTP_LOGV("not found, new connection id:%d\n", m_new_connection);

			boost::shared_ptr<socket_type> c(new (std::nothrow) socket_type(m_sock.get_io_service()));
			if (!c) return false;
			instantiate_connection(m_sock.get_io_service(), proxy_settings(), *c, 0, this);
			utp_stream* str = c->get<utp_stream>();
			TORRENT_ASSERT(str);
			bool ret = utp_incoming_packet(str->get_impl(), p, size, ep, receive_time);
			if (!ret) return false;
			m_cb(c);
			// the connection most likely changed its connection ID here
			// we need to move it to the correct ID
			return true;
		}

		// #error send reset

		return false;
	}

	void utp_socket_manager::remove_socket(boost::uint16_t id)
	{
		socket_map_t::iterator i = m_utp_sockets.find(id);
		if (i == m_utp_sockets.end()) return;
		delete_utp_impl(i->second);
		if (m_last_socket == i->second) m_last_socket = 0;
		m_utp_sockets.erase(i);
	}

	utp_socket_impl* utp_socket_manager::new_utp_socket(utp_stream* str)
	{
		boost::uint16_t send_id = 0;
		boost::uint16_t recv_id = 0;
		if (m_new_connection != -1)
		{
			send_id = m_new_connection;
			recv_id = m_new_connection + 1;
			m_new_connection = -1;
		}
		else
		{
			send_id = rand();
			recv_id = send_id - 1;
		}
		utp_socket_impl* impl = construct_utp_impl(recv_id, send_id, str, this);
		m_utp_sockets.insert(std::make_pair(recv_id, impl));
		return impl;
	}
}

<commit_msg>fix msvc build issue<commit_after>/*

Copyright (c) 2009, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/utp_stream.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/utp_socket_manager.hpp"
#include "libtorrent/instantiate_connection.hpp"
#include "libtorrent/socket_io.hpp"

// #define TORRENT_DEBUG_MTU 1135

namespace libtorrent
{

	utp_socket_manager::utp_socket_manager(session_settings const& sett, udp_socket& s
		, incoming_utp_callback_t cb)
		: m_sock(s)
		, m_cb(cb)
		, m_last_socket(0)
		, m_new_connection(-1)
		, m_sett(sett)
	{}

	utp_socket_manager::~utp_socket_manager()
	{
		for (socket_map_t::iterator i = m_utp_sockets.begin()
			, end(m_utp_sockets.end()); i != end; ++i)
		{
			delete_utp_impl(i->second);
		}
	}

	void utp_socket_manager::get_status(utp_status& s) const
	{
		s.num_idle = 0;
		s.num_syn_sent = 0;
		s.num_connected = 0;
		s.num_fin_sent = 0;
		s.num_close_wait = 0;

		for (socket_map_t::const_iterator i = m_utp_sockets.begin()
			, end(m_utp_sockets.end()); i != end; ++i)
		{
			int state = utp_socket_state(i->second);
			switch (state)
			{
				case 0: ++s.num_idle; break;
				case 1: ++s.num_syn_sent; break;
				case 2: ++s.num_connected; break;
				case 3: ++s.num_fin_sent; break;
				case 4: ++s.num_close_wait; break;
				case 5: ++s.num_close_wait; break;
			}
		}
	}

	void utp_socket_manager::tick(ptime now)
	{
		for (socket_map_t::iterator i = m_utp_sockets.begin()
			, end(m_utp_sockets.end()); i != end;)
		{
			if (should_delete(i->second))
			{
				delete_utp_impl(i->second);
				if (m_last_socket == i->second) m_last_socket = 0;
				m_utp_sockets.erase(i++);
				continue;
			}
			tick_utp_impl(i->second, now);
			++i;
		}
	}

	void utp_socket_manager::send_packet(udp::endpoint const& ep, char const* p
		, int len, error_code& ec, int flags)
	{
		if (!m_sock.is_open())
		{
			ec = asio::error::operation_aborted;
			return;
		}

#ifdef TORRENT_DEBUG_MTU
		// drop packets that exceed the debug MTU
		if ((flags & dont_fragment) && len > TORRENT_DEBUG_MTU) return;
#endif

#ifdef TORRENT_HAS_DONT_FRAGMENT
		error_code tmp;
		if (flags & utp_socket_manager::dont_fragment)
			m_sock.set_option(libtorrent::dont_fragment(true), tmp);
#endif
		m_sock.send(ep, p, len, ec);
#ifdef TORRENT_HAS_DONT_FRAGMENT
		if (flags & utp_socket_manager::dont_fragment)
			m_sock.set_option(libtorrent::dont_fragment(false), tmp);
#endif
	}

	tcp::endpoint utp_socket_manager::local_endpoint(error_code& ec) const
	{
		return m_sock.local_endpoint(ec);
	}

	bool utp_socket_manager::incoming_packet(char const* p, int size, udp::endpoint const& ep)
	{
//		UTP_LOGV("incoming packet size:%d\n", size);

		if (size < sizeof(utp_header)) return false;

		utp_header const* ph = (utp_header*)p;

//		UTP_LOGV("incoming packet version:%d\n", int(ph->get_version()));

		if (ph->get_version() != 1) return false;

		const ptime receive_time = time_now_hires();

		// parse out connection ID and look for existing
		// connections. If found, forward to the utp_stream.
		boost::uint16_t id = ph->connection_id;

		// first test to see if it's the same socket as last time
		// in most cases it is
		if (m_last_socket
			&& utp_match(m_last_socket, ep, id))
		{
			return utp_incoming_packet(m_last_socket, p, size, ep, receive_time);
		}

		socket_map_t::iterator i = m_utp_sockets.find(id);

		std::pair<socket_map_t::iterator, socket_map_t::iterator> r =
			m_utp_sockets.equal_range(id);

		for (; r.first != r.second; ++r.first)
		{
			if (!utp_match(r.first->second, ep, id)) continue;
			bool ret = utp_incoming_packet(r.first->second, p, size, ep, receive_time);
			if (ret) m_last_socket = r.first->second;
			return ret;
		}

//		UTP_LOGV("incoming packet id:%d source:%s\n", id, print_endpoint(ep).c_str());

		if (!m_sett.enable_incoming_utp)
			return false;

		// if not found, see if it's a SYN packet, if it is,
		// create a new utp_stream
		if (ph->get_type() == ST_SYN)
		{
			// create the new socket with this ID
			m_new_connection = id;

//			UTP_LOGV("not found, new connection id:%d\n", m_new_connection);

			boost::shared_ptr<socket_type> c(new (std::nothrow) socket_type(m_sock.get_io_service()));
			if (!c) return false;
			instantiate_connection(m_sock.get_io_service(), proxy_settings(), *c, 0, this);
			utp_stream* str = c->get<utp_stream>();
			TORRENT_ASSERT(str);
			bool ret = utp_incoming_packet(str->get_impl(), p, size, ep, receive_time);
			if (!ret) return false;
			m_cb(c);
			// the connection most likely changed its connection ID here
			// we need to move it to the correct ID
			return true;
		}

		// #error send reset

		return false;
	}

	void utp_socket_manager::remove_socket(boost::uint16_t id)
	{
		socket_map_t::iterator i = m_utp_sockets.find(id);
		if (i == m_utp_sockets.end()) return;
		delete_utp_impl(i->second);
		if (m_last_socket == i->second) m_last_socket = 0;
		m_utp_sockets.erase(i);
	}

	utp_socket_impl* utp_socket_manager::new_utp_socket(utp_stream* str)
	{
		boost::uint16_t send_id = 0;
		boost::uint16_t recv_id = 0;
		if (m_new_connection != -1)
		{
			send_id = m_new_connection;
			recv_id = m_new_connection + 1;
			m_new_connection = -1;
		}
		else
		{
			send_id = rand();
			recv_id = send_id - 1;
		}
		utp_socket_impl* impl = construct_utp_impl(recv_id, send_id, str, this);
		m_utp_sockets.insert(std::make_pair(recv_id, impl));
		return impl;
	}
}

<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// type_traits

// has_copy_assign

#include <type_traits>

int main()
{
    static_assert((std::has_copy_assign<int>::value), "");
}
<commit_msg>Hooked the following up to clang:  is_class, is_enum, has_nothrow_copy_assign, has_trivial_destructor, has_virtual_destructor, is_pod.  Implemented has_copy_assign.<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// type_traits

// has_copy_assign

#include <type_traits>

class Empty
{
};

class NotEmpty
{
public:
    virtual ~NotEmpty();
};

union Union {};

struct bit_zero
{
    int :  0;
};

struct A
{
    A();
};

int main()
{
    static_assert(( std::has_copy_assign<int>::value), "");
    static_assert((!std::has_copy_assign<const int>::value), "");
    static_assert((!std::has_copy_assign<int[]>::value), "");
    static_assert((!std::has_copy_assign<int[3]>::value), "");
    static_assert((!std::has_copy_assign<int&>::value), "");
    static_assert(( std::has_copy_assign<A>::value), "");
    static_assert(( std::has_copy_assign<bit_zero>::value), "");
    static_assert(( std::has_copy_assign<Union>::value), "");
    static_assert(( std::has_copy_assign<NotEmpty>::value), "");
    static_assert(( std::has_copy_assign<Empty>::value), "");
}
<|endoftext|>


<commit_before>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2014 Steven Lovegrove
 *
 * 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.
 */

#include <pangolin/video/drivers/join.h>
#include <pangolin/utils/timer.h>

namespace pangolin
{
VideoJoiner::VideoJoiner(const std::vector<VideoInterface*>& src)
    : src(src), size_bytes(0), sync_attempts_to_go(-1), sync_continuously(false)
{
    // Add individual streams
    for(size_t s=0; s< src.size(); ++s)
    {
        VideoInterface& vid = *src[s];
        for(size_t i=0; i < vid.Streams().size(); ++i)
        {
            const StreamInfo si = vid.Streams()[i];
            const VideoPixelFormat fmt = si.PixFormat();
            const Image<unsigned char> img_offset = si.StreamImage((unsigned char*)size_bytes);
            streams.push_back(StreamInfo(fmt, img_offset));
        }
        size_bytes += src[s]->SizeBytes();
    }
}

VideoJoiner::~VideoJoiner()
{
    for(size_t s=0; s< src.size(); ++s) {
        src[s]->Stop();
        delete src[s];
    }
}

size_t VideoJoiner::SizeBytes() const
{
    return size_bytes;
}

const std::vector<StreamInfo>& VideoJoiner::Streams() const
{
    return streams;
}

void VideoJoiner::Start()
{
    for(size_t s=0; s< src.size(); ++s) {
        src[s]->Start();
    }
}

void VideoJoiner::Stop()
{
    for(size_t s=0; s< src.size(); ++s) {
        src[s]->Stop();
    }
}

bool VideoJoiner::Sync(int64_t tolerance_us, bool continuous)
{
    for(size_t s=0; s< src.size(); ++s)
    {
       VideoPropertiesInterface* vpi = dynamic_cast<VideoPropertiesInterface*>(src[s]);
       if(!vpi)
         return false;
    }
    sync_attempts_to_go = MAX_SYNC_ATTEMPTS;
    sync_tolerance_us = tolerance_us;
    sync_continuously = continuous;
    return true;
}

bool VideoJoiner::GrabNext( unsigned char* image, bool wait )
{
    size_t offset = 0;
    std::vector<size_t> offsets;
    std::vector<int64_t> reception_times;
    int64_t newest = std::numeric_limits<int64_t>::min();
    int64_t oldest = std::numeric_limits<int64_t>::max();
    bool grabbed_any = false;

    for(size_t s=0; s<src.size(); ++s) {
       VideoInterface& vid = *src[s];
       grabbed_any |= vid.GrabNext(image+offset,wait);
       offsets.push_back(offset);
       offset += vid.SizeBytes();
       if(sync_attempts_to_go >= 0) {
          VideoPropertiesInterface* vidpi = dynamic_cast<VideoPropertiesInterface*>(src[s]);
          if(vidpi->FrameProperties().contains(PANGO_HOST_RECEPTION_TIME_US)) {
             int64_t rt = vidpi->FrameProperties()[PANGO_HOST_RECEPTION_TIME_US].get<int64_t>();
             reception_times.push_back(rt);
             if(newest < rt) newest = rt;
             if(oldest > rt) oldest = rt;
          } else {
             sync_attempts_to_go = -1;
             pango_print_error("Stream %lu in join does not support startup_sync_us option.\n", s);
          }
       }
    }

    if((sync_continuously || (sync_attempts_to_go == 0)) && ((newest - oldest) > sync_tolerance_us) ){
       pango_print_warn("Join error, unable to sync streams within %lu us\n", (unsigned long)sync_tolerance_us);
    }

    if(sync_attempts_to_go >= 0) {
       for(size_t s=0; s<src.size(); ++s) {
          if(reception_times[s] < (newest - sync_tolerance_us)) {
             VideoInterface& vid = *src[s];
             vid.GrabNewest(image+offsets[s],false);
          }
       }
       if(!sync_continuously) --sync_attempts_to_go;
    }

    return grabbed_any;
}

bool VideoJoiner::GrabNewest( unsigned char* image, bool wait )
{
  // Simply calling GrabNewest on the child streams might cause loss of sync,
  // instead we perform as many GrabNext as possible on the first stream and
  // then pull the same number of frames from every other stream.

  size_t offset = 0;
  std::vector<size_t> offsets;
  std::vector<int64_t> reception_times;
  int64_t newest = std::numeric_limits<int64_t>::min();
  int64_t oldest = std::numeric_limits<int64_t>::max();
  bool grabbed_any = false;
  int first_stream_backlog = 0;
  int64_t rt = 0;
  pangolin::basetime start,last,now;

  start = pangolin::TimeNow();
  last = start;
  bool got_frame = false;
  do {
      got_frame = src[0]->GrabNext(image+offset,false);
      if(got_frame) {
          if(sync_attempts_to_go >= 0) {
              VideoPropertiesInterface* vidpi = dynamic_cast<VideoPropertiesInterface*>(src[0]);
              if(vidpi->FrameProperties().contains(PANGO_HOST_RECEPTION_TIME_US)) {
                  rt = vidpi->FrameProperties()[PANGO_HOST_RECEPTION_TIME_US].get<int64_t>();
              } else {
                  sync_attempts_to_go = -1;
                  pango_print_error("Stream %u in join does not support startup_sync_us option.\n", 0);
              }
          }
          first_stream_backlog++;
          grabbed_any = true;
      }
  } while(got_frame);
  offsets.push_back(offset);
  offset += src[0]->SizeBytes();
  if(sync_attempts_to_go >= 0) {
      reception_times.push_back(rt);
      if(newest < rt) newest = rt;
      if(oldest > rt) oldest = rt;
  }
  now = pangolin::TimeNow();
  std::cout << "JOIN: Stream 1 grab: " << 1000*pangolin::TimeDiff_s(last, now) << "ms" << std::endl;
  last = now;

  for(size_t s=1; s<src.size(); ++s) {
      for (int i=0; i<first_stream_backlog; i++){
          grabbed_any |= src[s]->GrabNext(image+offset,true);
          if(sync_attempts_to_go >= 0) {
              VideoPropertiesInterface* vidpi = dynamic_cast<VideoPropertiesInterface*>(src[s]);
              if(vidpi->FrameProperties().contains(PANGO_HOST_RECEPTION_TIME_US)) {
                  rt = vidpi->FrameProperties()[PANGO_HOST_RECEPTION_TIME_US].get<int64_t>();
              } else {
                  sync_attempts_to_go = -1;
                  pango_print_error("Stream %lu in join does not support startup_sync_us option.\n", s);
              }
          }
      }
      offsets.push_back(offset);
      offset += src[s]->SizeBytes();
      if(sync_attempts_to_go >= 0) {
          reception_times.push_back(rt);
          if(newest < rt) newest = rt;
          if(oldest > rt) oldest = rt;
      }
  }
  now = pangolin::TimeNow();
  std::cout << "JOIN: Stream 2 grab: " << 1000*pangolin::TimeDiff_s(last, now) << "ms" << std::endl;
  last = now;

  if((sync_continuously || (sync_attempts_to_go == 0)) && ((newest - oldest) > sync_tolerance_us) ){
     pango_print_warn("Join error, unable to sync streams within %lu us\n", (unsigned long)sync_tolerance_us);
  }

  if(sync_attempts_to_go >= 0) {
     for(size_t s=0; s<src.size(); ++s) {
        if(reception_times[s] < (newest - sync_tolerance_us)) {
           VideoInterface& vid = *src[s];
           vid.GrabNewest(image+offsets[s],false);
        }
     }
     if(!sync_continuously) --sync_attempts_to_go;
  }
  now = pangolin::TimeNow();
  std::cout << "JOIN: Sync: " << 1000*pangolin::TimeDiff_s(last, now) << "ms" << std::endl;
  last = now;

  return grabbed_any;
}

std::vector<VideoInterface*>& VideoJoiner::InputStreams()
{
    return src;
}

}
<commit_msg>Revert "Join timing"<commit_after>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2014 Steven Lovegrove
 *
 * 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.
 */

#include <pangolin/video/drivers/join.h>

namespace pangolin
{
VideoJoiner::VideoJoiner(const std::vector<VideoInterface*>& src)
    : src(src), size_bytes(0), sync_attempts_to_go(-1), sync_continuously(false)
{
    // Add individual streams
    for(size_t s=0; s< src.size(); ++s)
    {
        VideoInterface& vid = *src[s];
        for(size_t i=0; i < vid.Streams().size(); ++i)
        {
            const StreamInfo si = vid.Streams()[i];
            const VideoPixelFormat fmt = si.PixFormat();
            const Image<unsigned char> img_offset = si.StreamImage((unsigned char*)size_bytes);
            streams.push_back(StreamInfo(fmt, img_offset));
        }
        size_bytes += src[s]->SizeBytes();
    }
}

VideoJoiner::~VideoJoiner()
{
    for(size_t s=0; s< src.size(); ++s) {
        src[s]->Stop();
        delete src[s];
    }
}

size_t VideoJoiner::SizeBytes() const
{
    return size_bytes;
}

const std::vector<StreamInfo>& VideoJoiner::Streams() const
{
    return streams;
}

void VideoJoiner::Start()
{
    for(size_t s=0; s< src.size(); ++s) {
        src[s]->Start();
    }
}

void VideoJoiner::Stop()
{
    for(size_t s=0; s< src.size(); ++s) {
        src[s]->Stop();
    }
}

bool VideoJoiner::Sync(int64_t tolerance_us, bool continuous)
{
    for(size_t s=0; s< src.size(); ++s)
    {
       VideoPropertiesInterface* vpi = dynamic_cast<VideoPropertiesInterface*>(src[s]);
       if(!vpi)
         return false;
    }
    sync_attempts_to_go = MAX_SYNC_ATTEMPTS;
    sync_tolerance_us = tolerance_us;
    sync_continuously = continuous;
    return true;
}

bool VideoJoiner::GrabNext( unsigned char* image, bool wait )
{
    size_t offset = 0;
    std::vector<size_t> offsets;
    std::vector<int64_t> reception_times;
    int64_t newest = std::numeric_limits<int64_t>::min();
    int64_t oldest = std::numeric_limits<int64_t>::max();
    bool grabbed_any = false;

    for(size_t s=0; s<src.size(); ++s) {
       VideoInterface& vid = *src[s];
       grabbed_any |= vid.GrabNext(image+offset,wait);
       offsets.push_back(offset);
       offset += vid.SizeBytes();
       if(sync_attempts_to_go >= 0) {
          VideoPropertiesInterface* vidpi = dynamic_cast<VideoPropertiesInterface*>(src[s]);
          if(vidpi->FrameProperties().contains(PANGO_HOST_RECEPTION_TIME_US)) {
             int64_t rt = vidpi->FrameProperties()[PANGO_HOST_RECEPTION_TIME_US].get<int64_t>();
             reception_times.push_back(rt);
             if(newest < rt) newest = rt;
             if(oldest > rt) oldest = rt;
          } else {
             sync_attempts_to_go = -1;
             pango_print_error("Stream %lu in join does not support startup_sync_us option.\n", s);
          }
       }
    }

    if((sync_continuously || (sync_attempts_to_go == 0)) && ((newest - oldest) > sync_tolerance_us) ){
       pango_print_warn("Join error, unable to sync streams within %lu us\n", (unsigned long)sync_tolerance_us);
    }

    if(sync_attempts_to_go >= 0) {
       for(size_t s=0; s<src.size(); ++s) {
          if(reception_times[s] < (newest - sync_tolerance_us)) {
             VideoInterface& vid = *src[s];
             vid.GrabNewest(image+offsets[s],false);
          }
       }
       if(!sync_continuously) --sync_attempts_to_go;
    }

    return grabbed_any;
}

bool VideoJoiner::GrabNewest( unsigned char* image, bool wait )
{
  // Simply calling GrabNewest on the child streams might cause loss of sync,
  // instead we perform as many GrabNext as possible on the first stream and
  // then pull the same number of frames from every other stream.

  size_t offset = 0;
  std::vector<size_t> offsets;
  std::vector<int64_t> reception_times;
  int64_t newest = std::numeric_limits<int64_t>::min();
  int64_t oldest = std::numeric_limits<int64_t>::max();
  bool grabbed_any = false;
  int first_stream_backlog = 0;
  int64_t rt = 0;

  bool got_frame = false;
  do {
      got_frame = src[0]->GrabNext(image+offset,false);
      if(got_frame) {
          if(sync_attempts_to_go >= 0) {
              VideoPropertiesInterface* vidpi = dynamic_cast<VideoPropertiesInterface*>(src[0]);
              if(vidpi->FrameProperties().contains(PANGO_HOST_RECEPTION_TIME_US)) {
                  rt = vidpi->FrameProperties()[PANGO_HOST_RECEPTION_TIME_US].get<int64_t>();
              } else {
                  sync_attempts_to_go = -1;
                  pango_print_error("Stream %u in join does not support startup_sync_us option.\n", 0);
              }
          }
          first_stream_backlog++;
          grabbed_any = true;
      }
  } while(got_frame);
  offsets.push_back(offset);
  offset += src[0]->SizeBytes();
  if(sync_attempts_to_go >= 0) {
      reception_times.push_back(rt);
      if(newest < rt) newest = rt;
      if(oldest > rt) oldest = rt;
  }

  for(size_t s=1; s<src.size(); ++s) {
      for (int i=0; i<first_stream_backlog; i++){
          grabbed_any |= src[s]->GrabNext(image+offset,true);
          if(sync_attempts_to_go >= 0) {
              VideoPropertiesInterface* vidpi = dynamic_cast<VideoPropertiesInterface*>(src[s]);
              if(vidpi->FrameProperties().contains(PANGO_HOST_RECEPTION_TIME_US)) {
                  rt = vidpi->FrameProperties()[PANGO_HOST_RECEPTION_TIME_US].get<int64_t>();
              } else {
                  sync_attempts_to_go = -1;
                  pango_print_error("Stream %lu in join does not support startup_sync_us option.\n", s);
              }
          }
      }
      offsets.push_back(offset);
      offset += src[s]->SizeBytes();
      if(sync_attempts_to_go >= 0) {
          reception_times.push_back(rt);
          if(newest < rt) newest = rt;
          if(oldest > rt) oldest = rt;
      }
  }

  if((sync_continuously || (sync_attempts_to_go == 0)) && ((newest - oldest) > sync_tolerance_us) ){
     pango_print_warn("Join error, unable to sync streams within %lu us\n", (unsigned long)sync_tolerance_us);
  }

  if(sync_attempts_to_go >= 0) {
     for(size_t s=0; s<src.size(); ++s) {
        if(reception_times[s] < (newest - sync_tolerance_us)) {
           VideoInterface& vid = *src[s];
           vid.GrabNewest(image+offsets[s],false);
        }
     }
     if(!sync_continuously) --sync_attempts_to_go;
  }

  return grabbed_any;
}

std::vector<VideoInterface*>& VideoJoiner::InputStreams()
{
    return src;
}

}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh/fe_transformation_base.h"
#include "libmesh/h1_fe_transformation.h"
#include "libmesh/hcurl_fe_transformation.h"

namespace libMesh
{

  template< typename OutputShape >
  AutoPtr<FETransformationBase<OutputShape> > FETransformationBase<OutputShape>::build( const FEType& fe_type )
  {
    switch( fe_type.family )
      {
	/* H1 Conforming Elements */
      case LAGRANGE:
      case HIERARCHIC:
      case BERNSTEIN:
      case SZABAB:
      case CLOUGH: /* PB: Really H2 */
      case HERMITE: /* PB: Really H2 */
      case LAGRANGE_VEC:
      case MONOMIAL: /* PB: Shouldn't this be L2 conforming? */
      case XYZ: /* PB: Shouldn't this be L2 conforming? */
      case L2_HIERARCHIC: /* PB: Shouldn't this be L2 conforming? */
      case L2_LAGRANGE: /* PB: Shouldn't this be L2 conforming? */
      case JACOBI_20_00: /* PB: For infinite elements... */
      case JACOBI_30_00: /* PB: For infinite elements... */
	{
	  AutoPtr<FETransformationBase<OutputShape> > ap( new H1FETransformation<OutputShape> );
	  return ap;
	}
	/* HCurl Conforming Elements */
      case NEDELEC_ONE:
	{
	  AutoPtr<FETransformationBase<OutputShape> > ap( new HCurlFETransformation<OutputShape> );
	  return ap;
	}

	/* HDiv Conforming Elements */
	/* L2 Conforming Elements */

	/* Other... */
      case SCALAR:
	{
	  // Should never need this for SCALARs
	  AutoPtr<FETransformationBase<OutputShape> > ap( NULL );
	  return ap;
	}

      default:
	libmesh_error();
      }

    // Should never get here...
    libmesh_error();
    AutoPtr<FETransformationBase<OutputShape> > ap( NULL );
    return ap;
  }

template class FETransformationBase<Real>;
template class FETransformationBase<RealGradient>;

} // namespace libMesh
<commit_msg>Actually use an FETransformation for SCALAR elements and not NULL...<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh/fe_transformation_base.h"
#include "libmesh/h1_fe_transformation.h"
#include "libmesh/hcurl_fe_transformation.h"

namespace libMesh
{

  template< typename OutputShape >
  AutoPtr<FETransformationBase<OutputShape> > FETransformationBase<OutputShape>::build( const FEType& fe_type )
  {
    switch( fe_type.family )
      {
	/* H1 Conforming Elements */
      case LAGRANGE:
      case HIERARCHIC:
      case BERNSTEIN:
      case SZABAB:
      case CLOUGH: /* PB: Really H2 */
      case HERMITE: /* PB: Really H2 */
      case LAGRANGE_VEC:
      case MONOMIAL: /* PB: Shouldn't this be L2 conforming? */
      case XYZ: /* PB: Shouldn't this be L2 conforming? */
      case L2_HIERARCHIC: /* PB: Shouldn't this be L2 conforming? */
      case L2_LAGRANGE: /* PB: Shouldn't this be L2 conforming? */
      case JACOBI_20_00: /* PB: For infinite elements... */
      case JACOBI_30_00: /* PB: For infinite elements... */
	{
	  AutoPtr<FETransformationBase<OutputShape> > ap( new H1FETransformation<OutputShape> );
	  return ap;
	}
	/* HCurl Conforming Elements */
      case NEDELEC_ONE:
	{
	  AutoPtr<FETransformationBase<OutputShape> > ap( new HCurlFETransformation<OutputShape> );
	  return ap;
	}

	/* HDiv Conforming Elements */
	/* L2 Conforming Elements */

	/* Other... */
      case SCALAR:
	{
	  // Should never need this for SCALARs
	  AutoPtr<FETransformationBase<OutputShape> > ap( new H1FETransformation<OutputShape> );
	  return ap;
	}

      default:
	libmesh_error();
      }

    // Should never get here...
    libmesh_error();
    AutoPtr<FETransformationBase<OutputShape> > ap( NULL );
    return ap;
  }

template class FETransformationBase<Real>;
template class FETransformationBase<RealGradient>;

} // namespace libMesh
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
// Copyright (C) 2006-2010 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#ifdef _MSC_VER
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4996)
#endif

#include <stdlib.h>
#include <iostream>
#include <fstream>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <vw/Core/Cache.h>
#include <vw/Core/ProgressCallback.h>
#include <vw/Math/Matrix.h>
#include <vw/Image/Transform.h>
#include <vw/Image/Palette.h>
#include <vw/FileIO/DiskImageResource.h>
#include <vw/FileIO/DiskImageResourceJPEG.h>
#include <vw/FileIO/DiskImageResourcePNG.h>
#include <vw/FileIO/DiskImageResourceGDAL.h>
#include <vw/FileIO/DiskImageView.h>
#include <vw/Cartography/GeoReference.h>
#include <vw/Cartography/GeoTransform.h>
#include <vw/Cartography/FileIO.h>
#include <vw/Mosaic/ImageComposite.h>
#include <vw/Mosaic/QuadTreeGenerator.h>
#include <vw/Mosaic/KMLQuadTreeConfig.h>

using namespace vw;
using namespace vw::cartography;
using namespace vw::mosaic;

class uint16_to_rgba8 : public ReturnFixedType<PixelRGBA<uint8> > {
  uint16 minval, maxval;
  double scale;
public:
  uint16_to_rgba8( uint16 minval, uint16 maxval ) : minval(minval), maxval(maxval), scale(255.0/(maxval-minval)) {}
  PixelRGBA<uint8> operator()( uint16 pix ) const {
    if( pix == 0 ) return PixelRGBA<uint8>();
    uint8 val = (uint8) ( scale * (pix - minval) );
    if( pix < minval ) val = 0;
    else if( pix > maxval ) val = 255;
    return PixelRGBA<uint8>( val, val, val, 255 );
  }
};

class rgb16_to_rgba8 : public ReturnFixedType<PixelRGBA<uint8> > {
  uint16 minval_r, maxval_r;
  double scale_r;
  uint16 minval_g, maxval_g;
  double scale_g;
  uint16 minval_b, maxval_b;
  double scale_b;
public:
  rgb16_to_rgba8( uint16 minval_r, uint16 maxval_r, uint16 minval_g, uint16 maxval_g, uint16 minval_b, uint16 maxval_b )
    : minval_r(minval_r), maxval_r(maxval_r), scale_r(255.0/(maxval_r-minval_r)),
      minval_g(minval_g), maxval_g(maxval_g), scale_g(255.0/(maxval_g-minval_g)),
      minval_b(minval_b), maxval_b(maxval_b), scale_b(255.0/(maxval_b-minval_b))
  {}
  PixelRGBA<uint8> operator()( PixelRGB<uint16> const& pix ) const {
  if( pix.r()==0 || pix.g()==0 || pix.b()==0 ) return PixelRGBA<uint8>();
  PixelRGBA<uint8> result( (uint8)(scale_r*(pix.r()-minval_r)), (uint8)(scale_g*(pix.g()-minval_g)), (uint8)(scale_b*(pix.b()-minval_b)), 255 );
  if( pix.r() < minval_r ) result.r() = 0;
  else if( pix.r() > maxval_r ) result.r() = 255;
  if( pix.g() < minval_g ) result.g() = 0;
  else if( pix.g() > maxval_g ) result.g() = 255;
  if( pix.b() < minval_b ) result.b() = 0;
  else if( pix.b() > maxval_b ) result.b() = 255;
  return result;
  }
};

PixelRGB<uint8> rgba8_to_rgb8( PixelRGBA<uint8> const& rgba ) {
  if( rgba.a() != 255 ) return PixelRGB<uint8>();
  else return PixelRGB<uint8>( rgba );
}

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

  std::vector<std::string> image_files;
  std::string output_file_name;
  std::string output_file_type;
  float jpeg_quality;
  int png_compression;
  unsigned cache_size;
  int draw_order_offset;
  int max_lod_pixels;
  int levels=0;
  int aspect_ratio=0;

  po::options_description general_options("General Options");
  general_options.add_options()
    ("output-name,o", po::value<std::string>(&output_file_name)->default_value("output"), "Specify the base output filename")
    ("quiet,q", "Quiet output")
    ("verbose,v", "Verbose output")
    ("cache", po::value<unsigned>(&cache_size)->default_value(1024), "Cache size, in megabytes")
    ("help", "Display this help message");

  po::options_description output_options("Output Options");
  output_options.add_options()
    ("file-type", po::value<std::string>(&output_file_type)->default_value("auto"), "Output file type")
    ("jpeg-quality", po::value<float>(&jpeg_quality)->default_value(0.95), "JPEG quality factor (0.0 to 1.0)")
    ("png-compression", po::value<int>(&png_compression)->default_value(3), "PNG compression level (0 to 9)")
    ("draw-order-offset", po::value<int>(&draw_order_offset)->default_value(0), "Set an offset for the KML <drawOrder> tag for this overlay")
    ("max-lod-pixels", po::value<int>(&max_lod_pixels)->default_value(1024), "Max LoD in pixels, or -1 for none (kml only)")
    ("levels", po::value<int>(&levels), "Number of levels in the global quadtree")
    ("alpha", "Output an alpha-masked geotiff")
    ("aspect-ratio", po::value<int>(&aspect_ratio)->default_value(1),"Pixel aspect ratio (for polar overlays; should be a power of two)");

  po::options_description hidden_options("");
  hidden_options.add_options()
    ("input-file", po::value<std::vector<std::string> >(&image_files));

  po::options_description options("Allowed Options");
  options.add(general_options).add(output_options).add(hidden_options);

  po::positional_options_description p;
  p.add("input-file", -1);

  po::variables_map vm;
  po::store( po::command_line_parser( argc, argv ).options(options).positional(p).run(), vm );
  po::notify( vm );

  std::ostringstream usage;
  usage << "Usage: image2kml [options] <filename>..." << std::endl << std::endl;
  usage << general_options << std::endl;
  usage << output_options << std::endl;

  if( vm.count("help") ) {
    std::cout << usage.str();
    return 1;
  }

  if( vm.count("input-file") < 1 ) {
    std::cout << "Error: Must specify at least one input file!" << std::endl << std::endl;
    std::cout << usage.str();
    return 1;
  }

  TerminalProgressCallback tpc("plate.tools.hirise2tif", "");
  const ProgressCallback *progress = &tpc;
  if( vm.count("verbose") ) {
    set_debug_level(VerboseDebugMessage);
    progress = &ProgressCallback::dummy_instance();
  }
  else if( vm.count("quiet") ) {
    set_debug_level(WarningMessage);
  }

  DiskImageResourceJPEG::set_default_quality( jpeg_quality );
  DiskImageResourcePNG::set_default_compression_level( png_compression );
  vw_settings().set_system_cache_size( cache_size*1024*1024 );

  uint16 min_gray=1024, max_gray=0, min_i=1024, max_i=0, min_r=1024, max_r=0, min_b=1024, max_b=0;

  int filter = 128;
  if( image_files.size() > 1 ) {
    std::cout << "Scanning IRB image for autoscaling..." << std::endl;
    DiskImageView<PixelRGB<uint16> > image( image_files[1] );
    ImageView<PixelRGB<uint16> > stripe( image.cols(), filter );
    TerminalProgressCallback progress("plate.tools.hirise2tif", "");
    for( int y=0; y+filter-1<image.rows(); y+=filter ) {
      progress.report_progress( (double)y / image.rows() );
      stripe = crop( image, 0, y, image.cols(), filter );
      ImageView<PixelRGB<uint16> >::pixel_accessor col = stripe.origin();
      for( int x=0; x+filter-1<image.cols(); x+=filter ) {
        int i=0,r=0,b=0,n=0;
        ImageView<PixelRGB<uint16> >::pixel_accessor row = col;
        for( int yy=0; yy<filter; ++yy ) {
          ImageView<PixelRGB<uint16> >::pixel_accessor pos = row;
          for( int xx=0; xx<filter; ++xx ) {
            PixelRGB<uint16> &val = *pos;
            pos.next_col();
            if( val.r()==0 || val.g()==0 || val.b()==0 ) continue;
            i += val.r();
            r += val.g();
            b += val.b();
            n ++;
          }
          row.next_row();
        }
        col.advance(filter,0);
        if( n < filter*filter/4 ) continue;
        if( i/n > max_i ) max_i = i/n;
        if( i/n < min_i ) min_i = i/n;
        if( r/n > max_r ) max_r = r/n;
        if( r/n < min_r ) min_r = r/n;
        if( b/n > max_b ) max_b = b/n;
        if( b/n < min_b ) min_b = b/n;
      }
    }
    progress.report_finished();
  }
  {
    std::cout << "Scanning red image for autoscaling..." << std::endl;
    DiskImageView<uint16> image( image_files[0] );
    ImageView<uint16> stripe( image.cols(), filter );
    TerminalProgressCallback progress;
    for( int y=0; y+filter-1<image.rows(); y+=filter ) {
      progress.report_progress( (double)y / image.rows() );
      stripe = crop( image, 0, y, image.cols(), filter );
      ImageView<uint16>::pixel_accessor col = stripe.origin();
      for( int x=0; x+filter-1<image.cols(); x+=filter ) {
        int r=0,n=0;
        ImageView<uint16>::pixel_accessor row = col;
        for( int yy=0; yy<filter; ++yy ) {
          ImageView<uint16>::pixel_accessor pos = row;
          for( int xx=0; xx<filter; ++xx ) {
            uint16 &val = *pos;
            pos.next_col();
            if( val == 0 ) continue;
            r += val;
            n ++;
          }
          row.next_row();
        }
        col.advance(filter,0);
        if( n < filter*filter/4 ) continue;
        if( r/n > max_gray ) max_gray = r/n;
        if( r/n < min_gray ) min_gray = r/n;
      }
    }
    progress.report_finished();
  }

  //std::cout << "GRAY: " << min_gray << " - " << max_gray << std::endl;
  //std::cout << "IR:   " << min_i << " - " << max_i << std::endl;
  //std::cout << "RED:  " << min_r << " - " << max_r << std::endl;
  //std::cout << "BLUE: " << min_b << " - " << max_b << std::endl;

  // Add the transformed input files to the composite
  ImageComposite<PixelRGBA<uint8> > composite;
  GeoReference master_georef;
  for( unsigned i=0; i<image_files.size(); ++i ) {
    DiskImageResourceGDAL *r = new DiskImageResourceGDAL( image_files[i] );
    GeoReference georef;
    read_georeference( georef, *r );
    if( i==0 ) master_georef = georef;
    Vector2 position = master_georef.lonlat_to_pixel( georef.pixel_to_lonlat( Vector2() ) );
    std::cout << position << std::endl;
    if( r->pixel_format() == VW_PIXEL_GRAY ) {
      composite.insert( per_pixel_filter( DiskImageView<uint16>( r ), uint16_to_rgba8(min_gray,max_gray) ),
                        math::impl::_round(position.x()), math::impl::_round(position.y()) );
    }
    else {
      composite.insert( per_pixel_filter( DiskImageView<PixelRGB<uint16> >( r ), rgb16_to_rgba8(min_i,max_i,min_r,max_r,min_b,max_b) ),
                        math::impl::_round(position.x()), math::impl::_round(position.y()) );
    }
  }

  // Update the georeference
  BBox2i pixel_bbox = composite.bbox();
  Vector2 offset = master_georef.pixel_to_point( pixel_bbox.min() ) - master_georef.pixel_to_point( Vector2() );
  Matrix3x3 M = master_georef.transform();
  M(0,2) += offset.x();
  M(1,2) += offset.y();
  if( ! master_georef.is_projected() ) {
    if( M(0,2) > 180 ) M(0,2) -= 360;
  }
  master_georef.set_transform( M );

  // Prepare the composite
  composite.set_draft_mode( true );
  composite.prepare();

  std::cout << "Generating output GeoTIFF..." << std::endl;
  DiskImageResourceGDAL::Options gdal_options;
  gdal_options["COMPRESS"] = "LZW";
  std::cout << "NAME: " << output_file_name << std::endl;
  ImageFormat format = composite.format();
  if( vm.count("alpha") ) {
    DiskImageResourceGDAL output_resource( output_file_name, format, Vector2i(256,256), gdal_options );
    write_georeference( output_resource, master_georef );
    std::cout << "Retaining alpha channel!" << std::endl;
    write_image( output_resource, composite, TerminalProgressCallback() );
  } else {
    format.pixel_format = VW_PIXEL_RGB;
    DiskImageResourceGDAL output_resource( output_file_name, format, Vector2i(256,256), gdal_options );
    write_georeference( output_resource, master_georef );
    std::cout << "Replacing alpha with black!" << std::endl;
    write_image( output_resource, per_pixel_filter(composite,&rgba8_to_rgb8), TerminalProgressCallback() );
  }

  return 0;
}
<commit_msg>turn off lzw, and force bigtiff, for hirise2tiff<commit_after>// __BEGIN_LICENSE__
// Copyright (C) 2006-2010 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#ifdef _MSC_VER
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4996)
#endif

#include <stdlib.h>
#include <iostream>
#include <fstream>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <vw/Core/Cache.h>
#include <vw/Core/ProgressCallback.h>
#include <vw/Math/Matrix.h>
#include <vw/Image/Transform.h>
#include <vw/Image/Palette.h>
#include <vw/FileIO/DiskImageResource.h>
#include <vw/FileIO/DiskImageResourceJPEG.h>
#include <vw/FileIO/DiskImageResourcePNG.h>
#include <vw/FileIO/DiskImageResourceGDAL.h>
#include <vw/FileIO/DiskImageView.h>
#include <vw/Cartography/GeoReference.h>
#include <vw/Cartography/GeoTransform.h>
#include <vw/Cartography/FileIO.h>
#include <vw/Mosaic/ImageComposite.h>
#include <vw/Mosaic/QuadTreeGenerator.h>
#include <vw/Mosaic/KMLQuadTreeConfig.h>

using namespace vw;
using namespace vw::cartography;
using namespace vw::mosaic;

class uint16_to_rgba8 : public ReturnFixedType<PixelRGBA<uint8> > {
  uint16 minval, maxval;
  double scale;
public:
  uint16_to_rgba8( uint16 minval, uint16 maxval ) : minval(minval), maxval(maxval), scale(255.0/(maxval-minval)) {}
  PixelRGBA<uint8> operator()( uint16 pix ) const {
    if( pix == 0 ) return PixelRGBA<uint8>();
    uint8 val = (uint8) ( scale * (pix - minval) );
    if( pix < minval ) val = 0;
    else if( pix > maxval ) val = 255;
    return PixelRGBA<uint8>( val, val, val, 255 );
  }
};

class rgb16_to_rgba8 : public ReturnFixedType<PixelRGBA<uint8> > {
  uint16 minval_r, maxval_r;
  double scale_r;
  uint16 minval_g, maxval_g;
  double scale_g;
  uint16 minval_b, maxval_b;
  double scale_b;
public:
  rgb16_to_rgba8( uint16 minval_r, uint16 maxval_r, uint16 minval_g, uint16 maxval_g, uint16 minval_b, uint16 maxval_b )
    : minval_r(minval_r), maxval_r(maxval_r), scale_r(255.0/(maxval_r-minval_r)),
      minval_g(minval_g), maxval_g(maxval_g), scale_g(255.0/(maxval_g-minval_g)),
      minval_b(minval_b), maxval_b(maxval_b), scale_b(255.0/(maxval_b-minval_b))
  {}
  PixelRGBA<uint8> operator()( PixelRGB<uint16> const& pix ) const {
  if( pix.r()==0 || pix.g()==0 || pix.b()==0 ) return PixelRGBA<uint8>();
  PixelRGBA<uint8> result( (uint8)(scale_r*(pix.r()-minval_r)), (uint8)(scale_g*(pix.g()-minval_g)), (uint8)(scale_b*(pix.b()-minval_b)), 255 );
  if( pix.r() < minval_r ) result.r() = 0;
  else if( pix.r() > maxval_r ) result.r() = 255;
  if( pix.g() < minval_g ) result.g() = 0;
  else if( pix.g() > maxval_g ) result.g() = 255;
  if( pix.b() < minval_b ) result.b() = 0;
  else if( pix.b() > maxval_b ) result.b() = 255;
  return result;
  }
};

PixelRGB<uint8> rgba8_to_rgb8( PixelRGBA<uint8> const& rgba ) {
  if( rgba.a() != 255 ) return PixelRGB<uint8>();
  else return PixelRGB<uint8>( rgba );
}

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

  std::vector<std::string> image_files;
  std::string output_file_name;
  std::string output_file_type;
  float jpeg_quality;
  int png_compression;
  unsigned cache_size;
  int draw_order_offset;
  int max_lod_pixels;
  int levels=0;
  int aspect_ratio=0;

  po::options_description general_options("General Options");
  general_options.add_options()
    ("output-name,o", po::value<std::string>(&output_file_name)->default_value("output"), "Specify the base output filename")
    ("quiet,q", "Quiet output")
    ("verbose,v", "Verbose output")
    ("cache", po::value<unsigned>(&cache_size)->default_value(1024), "Cache size, in megabytes")
    ("help", "Display this help message");

  po::options_description output_options("Output Options");
  output_options.add_options()
    ("file-type", po::value<std::string>(&output_file_type)->default_value("auto"), "Output file type")
    ("jpeg-quality", po::value<float>(&jpeg_quality)->default_value(0.95), "JPEG quality factor (0.0 to 1.0)")
    ("png-compression", po::value<int>(&png_compression)->default_value(3), "PNG compression level (0 to 9)")
    ("draw-order-offset", po::value<int>(&draw_order_offset)->default_value(0), "Set an offset for the KML <drawOrder> tag for this overlay")
    ("max-lod-pixels", po::value<int>(&max_lod_pixels)->default_value(1024), "Max LoD in pixels, or -1 for none (kml only)")
    ("levels", po::value<int>(&levels), "Number of levels in the global quadtree")
    ("alpha", "Output an alpha-masked geotiff")
    ("aspect-ratio", po::value<int>(&aspect_ratio)->default_value(1),"Pixel aspect ratio (for polar overlays; should be a power of two)");

  po::options_description hidden_options("");
  hidden_options.add_options()
    ("input-file", po::value<std::vector<std::string> >(&image_files));

  po::options_description options("Allowed Options");
  options.add(general_options).add(output_options).add(hidden_options);

  po::positional_options_description p;
  p.add("input-file", -1);

  po::variables_map vm;
  po::store( po::command_line_parser( argc, argv ).options(options).positional(p).run(), vm );
  po::notify( vm );

  std::ostringstream usage;
  usage << "Usage: image2kml [options] <filename>..." << std::endl << std::endl;
  usage << general_options << std::endl;
  usage << output_options << std::endl;

  if( vm.count("help") ) {
    std::cout << usage.str();
    return 1;
  }

  if( vm.count("input-file") < 1 ) {
    std::cout << "Error: Must specify at least one input file!" << std::endl << std::endl;
    std::cout << usage.str();
    return 1;
  }

  TerminalProgressCallback tpc("plate.tools.hirise2tif", "");
  const ProgressCallback *progress = &tpc;
  if( vm.count("verbose") ) {
    set_debug_level(VerboseDebugMessage);
    progress = &ProgressCallback::dummy_instance();
  }
  else if( vm.count("quiet") ) {
    set_debug_level(WarningMessage);
  }

  DiskImageResourceJPEG::set_default_quality( jpeg_quality );
  DiskImageResourcePNG::set_default_compression_level( png_compression );
  vw_settings().set_system_cache_size( cache_size*1024*1024 );

  uint16 min_gray=1024, max_gray=0, min_i=1024, max_i=0, min_r=1024, max_r=0, min_b=1024, max_b=0;

  int filter = 128;
  if( image_files.size() > 1 ) {
    std::cout << "Scanning IRB image for autoscaling..." << std::endl;
    DiskImageView<PixelRGB<uint16> > image( image_files[1] );
    ImageView<PixelRGB<uint16> > stripe( image.cols(), filter );
    TerminalProgressCallback progress("plate.tools.hirise2tif", "");
    for( int y=0; y+filter-1<image.rows(); y+=filter ) {
      progress.report_progress( (double)y / image.rows() );
      stripe = crop( image, 0, y, image.cols(), filter );
      ImageView<PixelRGB<uint16> >::pixel_accessor col = stripe.origin();
      for( int x=0; x+filter-1<image.cols(); x+=filter ) {
        int i=0,r=0,b=0,n=0;
        ImageView<PixelRGB<uint16> >::pixel_accessor row = col;
        for( int yy=0; yy<filter; ++yy ) {
          ImageView<PixelRGB<uint16> >::pixel_accessor pos = row;
          for( int xx=0; xx<filter; ++xx ) {
            PixelRGB<uint16> &val = *pos;
            pos.next_col();
            if( val.r()==0 || val.g()==0 || val.b()==0 ) continue;
            i += val.r();
            r += val.g();
            b += val.b();
            n ++;
          }
          row.next_row();
        }
        col.advance(filter,0);
        if( n < filter*filter/4 ) continue;
        if( i/n > max_i ) max_i = i/n;
        if( i/n < min_i ) min_i = i/n;
        if( r/n > max_r ) max_r = r/n;
        if( r/n < min_r ) min_r = r/n;
        if( b/n > max_b ) max_b = b/n;
        if( b/n < min_b ) min_b = b/n;
      }
    }
    progress.report_finished();
  }
  {
    std::cout << "Scanning red image for autoscaling..." << std::endl;
    DiskImageView<uint16> image( image_files[0] );
    ImageView<uint16> stripe( image.cols(), filter );
    TerminalProgressCallback progress;
    for( int y=0; y+filter-1<image.rows(); y+=filter ) {
      progress.report_progress( (double)y / image.rows() );
      stripe = crop( image, 0, y, image.cols(), filter );
      ImageView<uint16>::pixel_accessor col = stripe.origin();
      for( int x=0; x+filter-1<image.cols(); x+=filter ) {
        int r=0,n=0;
        ImageView<uint16>::pixel_accessor row = col;
        for( int yy=0; yy<filter; ++yy ) {
          ImageView<uint16>::pixel_accessor pos = row;
          for( int xx=0; xx<filter; ++xx ) {
            uint16 &val = *pos;
            pos.next_col();
            if( val == 0 ) continue;
            r += val;
            n ++;
          }
          row.next_row();
        }
        col.advance(filter,0);
        if( n < filter*filter/4 ) continue;
        if( r/n > max_gray ) max_gray = r/n;
        if( r/n < min_gray ) min_gray = r/n;
      }
    }
    progress.report_finished();
  }

  //std::cout << "GRAY: " << min_gray << " - " << max_gray << std::endl;
  //std::cout << "IR:   " << min_i << " - " << max_i << std::endl;
  //std::cout << "RED:  " << min_r << " - " << max_r << std::endl;
  //std::cout << "BLUE: " << min_b << " - " << max_b << std::endl;

  // Add the transformed input files to the composite
  ImageComposite<PixelRGBA<uint8> > composite;
  GeoReference master_georef;
  for( unsigned i=0; i<image_files.size(); ++i ) {
    DiskImageResourceGDAL *r = new DiskImageResourceGDAL( image_files[i] );
    GeoReference georef;
    read_georeference( georef, *r );
    if( i==0 ) master_georef = georef;
    Vector2 position = master_georef.lonlat_to_pixel( georef.pixel_to_lonlat( Vector2() ) );
    std::cout << position << std::endl;
    if( r->pixel_format() == VW_PIXEL_GRAY ) {
      composite.insert( per_pixel_filter( DiskImageView<uint16>( r ), uint16_to_rgba8(min_gray,max_gray) ),
                        math::impl::_round(position.x()), math::impl::_round(position.y()) );
    }
    else {
      composite.insert( per_pixel_filter( DiskImageView<PixelRGB<uint16> >( r ), rgb16_to_rgba8(min_i,max_i,min_r,max_r,min_b,max_b) ),
                        math::impl::_round(position.x()), math::impl::_round(position.y()) );
    }
  }

  // Update the georeference
  BBox2i pixel_bbox = composite.bbox();
  Vector2 offset = master_georef.pixel_to_point( pixel_bbox.min() ) - master_georef.pixel_to_point( Vector2() );
  Matrix3x3 M = master_georef.transform();
  M(0,2) += offset.x();
  M(1,2) += offset.y();
  if( ! master_georef.is_projected() ) {
    if( M(0,2) > 180 ) M(0,2) -= 360;
  }
  master_georef.set_transform( M );

  // Prepare the composite
  composite.set_draft_mode( true );
  composite.prepare();

  std::cout << "Generating output GeoTIFF..." << std::endl;
  DiskImageResourceGDAL::Options gdal_options;
  gdal_options["COMPRESS"] = "NONE";
  gdal_options["BIGTIFF"]  = "YES";

  std::cout << "NAME: " << output_file_name << std::endl;
  ImageFormat format = composite.format();
  if( vm.count("alpha") ) {
    DiskImageResourceGDAL output_resource( output_file_name, format, Vector2i(256,256), gdal_options );
    write_georeference( output_resource, master_georef );
    std::cout << "Retaining alpha channel!" << std::endl;
    write_image( output_resource, composite, TerminalProgressCallback() );
  } else {
    format.pixel_format = VW_PIXEL_RGB;
    DiskImageResourceGDAL output_resource( output_file_name, format, Vector2i(256,256), gdal_options );
    write_georeference( output_resource, master_georef );
    std::cout << "Replacing alpha with black!" << std::endl;
    write_image( output_resource, per_pixel_filter(composite,&rgba8_to_rgb8), TerminalProgressCallback() );
  }

  return 0;
}
<|endoftext|>