<commit_before>#include "filebrowserwidget.h"

#include <QFileSystemModel>

#include <QDesktopServices>
#include <QHeaderView>
#include <QSettings>

#define SETTINGS_SORTCOLUMN "_SortColumn"
#define SETTINGS_SORTORDER  "_SortOrder"

FileBrowserWidget::FileBrowserWidget(QWidget *pParent) :
    QTreeView(pParent),
    CommonWidget(pParent)
{
    mFileSystemModel = new QFileSystemModel;

    // We want acces to the full file system

    mFileSystemModel->setRootPath(QDir::rootPath());

    // Set some properties for the file browser widget itself

    setModel(mFileSystemModel);   // Associate ourselves to mFileSystemModel
    setSortingEnabled(true);      // Allow sorting
    setUniformRowHeights(true);   // Everything ought to be of the same height,
                                  // so set this property to true since it can
                                  // only speed things up which can't harm!
}

FileBrowserWidget::~FileBrowserWidget()
{
    delete mFileSystemModel;
}

void FileBrowserWidget::retranslateUi()
{
    // Nothing to do for now...
}

void FileBrowserWidget::defaultSettings()
{
    // Sort by ascending drive letters / paths

    sortByColumn(0, Qt::AscendingOrder);
}

void FileBrowserWidget::loadSettings(const QSettings &pSettings,
                                     const QString &pKey)
{
    // Retrieve the sorting information

    sortByColumn(pSettings.value(pKey+SETTINGS_SORTCOLUMN, 0).toInt(),
                 Qt::SortOrder(pSettings.value(pKey+SETTINGS_SORTORDER, Qt::AscendingOrder).toInt()));
}

void FileBrowserWidget::saveSettings(QSettings &pSettings, const QString &pKey)
{
    // Keep track of the sorting information

    pSettings.setValue(pKey+SETTINGS_SORTCOLUMN, header()->sortIndicatorSection());
    pSettings.setValue(pKey+SETTINGS_SORTORDER, header()->sortIndicatorOrder());
}

QSize FileBrowserWidget::sizeHint() const
{
    // Suggest a default size for the file browser widget
    // Note: this is critical if we want a docked widget, with a file browser
    //       widget on it, to have a decent size when docked to the main window

    return defaultSize(0.15);
}

void FileBrowserWidget::paintEvent(QPaintEvent *pEvent)
{
    QTreeView::paintEvent(pEvent);

    // Draw a border in case we are docked

    drawBorderIfDocked();
}
<commit_msg>To have mFileSystemModel->setRootPath(QDir::rootPath()); will, on Windows, set the root path to C:\ and thus prevent us from sorting things properly, so clearly not what we want! So, back to mFileSystemModel->setRootPath("");!<commit_after>#include "filebrowserwidget.h"

#include <QFileSystemModel>

#include <QDesktopServices>
#include <QHeaderView>
#include <QSettings>

#define SETTINGS_SORTCOLUMN "_SortColumn"
#define SETTINGS_SORTORDER  "_SortOrder"

FileBrowserWidget::FileBrowserWidget(QWidget *pParent) :
    QTreeView(pParent),
    CommonWidget(pParent)
{
    mFileSystemModel = new QFileSystemModel;

    // We want acces to the full file system

    mFileSystemModel->setRootPath("");

    // Set some properties for the file browser widget itself

    setModel(mFileSystemModel);   // Associate ourselves to mFileSystemModel
    setSortingEnabled(true);      // Allow sorting
    setUniformRowHeights(true);   // Everything ought to be of the same height,
                                  // so set this property to true since it can
                                  // only speed things up which can't harm!
}

FileBrowserWidget::~FileBrowserWidget()
{
    delete mFileSystemModel;
}

void FileBrowserWidget::retranslateUi()
{
    // Nothing to do for now...
}

void FileBrowserWidget::defaultSettings()
{
    // Sort by ascending drive letters / paths

    sortByColumn(0, Qt::AscendingOrder);
}

void FileBrowserWidget::loadSettings(const QSettings &pSettings,
                                     const QString &pKey)
{
    // Retrieve the sorting information

    sortByColumn(pSettings.value(pKey+SETTINGS_SORTCOLUMN, 0).toInt(),
                 Qt::SortOrder(pSettings.value(pKey+SETTINGS_SORTORDER, Qt::AscendingOrder).toInt()));
}

void FileBrowserWidget::saveSettings(QSettings &pSettings, const QString &pKey)
{
    // Keep track of the sorting information

    pSettings.setValue(pKey+SETTINGS_SORTCOLUMN, header()->sortIndicatorSection());
    pSettings.setValue(pKey+SETTINGS_SORTORDER, header()->sortIndicatorOrder());
}

QSize FileBrowserWidget::sizeHint() const
{
    // Suggest a default size for the file browser widget
    // Note: this is critical if we want a docked widget, with a file browser
    //       widget on it, to have a decent size when docked to the main window

    return defaultSize(0.15);
}

void FileBrowserWidget::paintEvent(QPaintEvent *pEvent)
{
    QTreeView::paintEvent(pEvent);

    // Draw a border in case we are docked

    drawBorderIfDocked();
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_MAT_FUN_PROMOTE_COMMON_HPP
#define STAN_MATH_PRIM_MAT_FUN_PROMOTE_COMMON_HPP

#include <stan/math/prim/mat/fun/common_type.hpp>
#include <stan/math/prim/mat/fun/promote_elements.hpp>

namespace stan {
  namespace math {

    /**
     * Return the result of promoting elements of a comtainer
     * to the wider of a pair of specified types.
     *
     * @tparam T1 first type
     * @tparam T2 second type
     * @tparam F type of elements
     * @param u elements to promote
     * @return the result of promoting elements
     */
    template <typename T1, typename T2, typename F>
    inline
    typename common_type<T1, T2>::type
    promote_common(const F& u) {
      return promote_elements<typename common_type<T1, T2>::type, F>
        ::promote(u);
    }

  }
}

#endif
<commit_msg>better doc comment<commit_after>#ifndef STAN_MATH_PRIM_MAT_FUN_PROMOTE_COMMON_HPP
#define STAN_MATH_PRIM_MAT_FUN_PROMOTE_COMMON_HPP

#include <stan/math/prim/mat/fun/common_type.hpp>
#include <stan/math/prim/mat/fun/promote_elements.hpp>

namespace stan {
  namespace math {

    /**
     * Return the result of promoting elements of a comtainer
     * to the wider of a pair of specified types.
     *
     * @tparam T1 first type
     * @tparam T2 second type
     * @tparam F container type (deduced from param u)
     * @param u elements to promote
     * @return the result of promoting elements
     */
    template <typename T1, typename T2, typename F>
    inline
    typename common_type<T1, T2>::type
    promote_common(const F& u) {
      return promote_elements<typename common_type<T1, T2>::type, F>
        ::promote(u);
    }

  }
}

#endif
<|endoftext|>


<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2015 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <assert.h>
#include <stdint.h>

#include "raul/Array.hpp"

#include "Buffer.hpp"
#include "Engine.hpp"
#include "BlockImpl.hpp"
#include "GraphImpl.hpp"
#include "PluginImpl.hpp"
#include "PortImpl.hpp"
#include "ProcessContext.hpp"
#include "ThreadManager.hpp"

using namespace std;

namespace Ingen {
namespace Server {

BlockImpl::BlockImpl(PluginImpl*         plugin,
                     const Raul::Symbol& symbol,
                     bool                polyphonic,
                     GraphImpl*          parent,
                     SampleRate          srate)
	: NodeImpl(plugin->uris(), parent, symbol)
	, _plugin(plugin)
	, _ports(NULL)
	, _context(Context::ID::AUDIO)
	, _polyphony((polyphonic && parent) ? parent->internal_poly() : 1)
	, _polyphonic(polyphonic)
	, _activated(false)
	, _enabled(true)
	, _traversed(false)
{
	assert(_plugin);
	assert(_polyphony > 0);
}

BlockImpl::~BlockImpl()
{
	if (_activated) {
		deactivate();
	}

	if (is_linked()) {
		parent_graph()->remove_block(*this);
	}

	delete _ports;
}

Node*
BlockImpl::port(uint32_t index) const
{
	return (*_ports)[index];
}

const Plugin*
BlockImpl::plugin() const
{
	return _plugin;
}

void
BlockImpl::activate(BufferFactory& bufs)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	_activated = true;
	for (uint32_t p = 0; p < num_ports(); ++p) {
		PortImpl* const port = _ports->at(p);
		port->activate(bufs);
	}
}

void
BlockImpl::deactivate()
{
	_activated = false;
	for (uint32_t p = 0; p < num_ports(); ++p) {
		PortImpl* const port = _ports->at(p);
		port->deactivate();
	}
}

bool
BlockImpl::prepare_poly(BufferFactory& bufs, uint32_t poly)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	if (!_polyphonic)
		poly = 1;

	if (_ports)
		for (uint32_t i = 0; i < _ports->size(); ++i)
			_ports->at(i)->prepare_poly(bufs, poly);

	return true;
}

bool
BlockImpl::apply_poly(ProcessContext& context, Raul::Maid& maid, uint32_t poly)
{
	if (!_polyphonic)
		poly = 1;

	_polyphony = poly;

	if (_ports)
		for (uint32_t i = 0; i < num_ports(); ++i)
			_ports->at(i)->apply_poly(context, maid, poly);

	return true;
}

void
BlockImpl::set_buffer_size(Context&       context,
                           BufferFactory& bufs,
                           LV2_URID       type,
                           uint32_t       size)
{
	if (_ports) {
		for (uint32_t i = 0; i < _ports->size(); ++i) {
			PortImpl* const p = _ports->at(i);
			if (p->buffer_type() == type) {
				p->set_buffer_size(context, bufs, size);
			}
		}
	}
}

PortImpl*
BlockImpl::nth_port_by_type(uint32_t n, bool input, PortType type)
{
	uint32_t count = 0;
	for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
		PortImpl* const port = _ports->at(i);
		if (port->is_input() == input && port->type() == type) {
			if (count++ == n) {
				return port;
			}
		}
	}
	return NULL;
}

PortImpl*
BlockImpl::port_by_symbol(const char* symbol)
{
	for (uint32_t p = 0; _ports && p < _ports->size(); ++p) {
		if (_ports->at(p)->symbol() == symbol) {
			return _ports->at(p);
		}
	}
	return NULL;
}

void
BlockImpl::pre_process(ProcessContext& context)
{
	// Mix down input ports
	for (uint32_t i = 0; i < num_ports(); ++i) {
		PortImpl* const port = _ports->at(i);
		port->pre_process(context);
		port->connect_buffers();
	}
}

void
BlockImpl::process(ProcessContext& context)
{
	pre_process(context);

	if (!_enabled) {
		for (PortType t : { PortType::AUDIO, PortType::CV, PortType::ATOM }) {
			for (uint32_t i = 0;; ++i) {
				PortImpl* in = nth_port_by_type(i, true, t);
				PortImpl* out;
				if (in && (out = nth_port_by_type(i, false, t))) {
					for (uint32_t v = 0; v < _polyphony; ++v) {
						out->buffer(v)->copy(context, in->buffer(v).get());
					}
				} else {
					break;
				}
			}
		}
		post_process(context);
		return;
	}

	ProcessContext subcontext(context);
	for (SampleCount offset = 0; offset < context.nframes();) {
		// Find earliest offset of a value change
		SampleCount chunk_end = context.nframes();
		for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
			PortImpl* const port = _ports->at(i);
			if (port->type() == PortType::CONTROL && port->is_input()) {
				const SampleCount o = port->next_value_offset(
					offset, context.nframes());
				if (o < chunk_end) {
					chunk_end = o;
				}
			}
		}

		// Slice context into a chunk from now until the next change
		subcontext.slice(offset, chunk_end - offset);

		// Prepare port buffers for reading, converting/mixing if necessary
		for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
			_ports->at(i)->connect_buffers(offset);
			_ports->at(i)->pre_run(subcontext);
		}

		// Run the chunk
		run(subcontext);

		offset = chunk_end;
		subcontext.slice(offset, chunk_end - offset);
	}

	post_process(context);
}

void
BlockImpl::post_process(ProcessContext& context)
{
	// Write output ports
	for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
		_ports->at(i)->post_process(context);
	}
}

void
BlockImpl::set_port_buffer(uint32_t    voice,
                           uint32_t    port_num,
                           BufferRef   buf,
                           SampleCount offset)
{
	/*std::cout << path() << " set port " << port_num << " voice " << voice
	  << " buffer " << buf << " offset " << offset << std::endl;*/
}

} // namespace Server
} // namespace Ingen
<commit_msg>Clear extra output buffers when bypassing blocks.<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2015 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <assert.h>
#include <stdint.h>

#include "raul/Array.hpp"

#include "Buffer.hpp"
#include "Engine.hpp"
#include "BlockImpl.hpp"
#include "GraphImpl.hpp"
#include "PluginImpl.hpp"
#include "PortImpl.hpp"
#include "ProcessContext.hpp"
#include "ThreadManager.hpp"

using namespace std;

namespace Ingen {
namespace Server {

BlockImpl::BlockImpl(PluginImpl*         plugin,
                     const Raul::Symbol& symbol,
                     bool                polyphonic,
                     GraphImpl*          parent,
                     SampleRate          srate)
	: NodeImpl(plugin->uris(), parent, symbol)
	, _plugin(plugin)
	, _ports(NULL)
	, _context(Context::ID::AUDIO)
	, _polyphony((polyphonic && parent) ? parent->internal_poly() : 1)
	, _polyphonic(polyphonic)
	, _activated(false)
	, _enabled(true)
	, _traversed(false)
{
	assert(_plugin);
	assert(_polyphony > 0);
}

BlockImpl::~BlockImpl()
{
	if (_activated) {
		deactivate();
	}

	if (is_linked()) {
		parent_graph()->remove_block(*this);
	}

	delete _ports;
}

Node*
BlockImpl::port(uint32_t index) const
{
	return (*_ports)[index];
}

const Plugin*
BlockImpl::plugin() const
{
	return _plugin;
}

void
BlockImpl::activate(BufferFactory& bufs)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	_activated = true;
	for (uint32_t p = 0; p < num_ports(); ++p) {
		PortImpl* const port = _ports->at(p);
		port->activate(bufs);
	}
}

void
BlockImpl::deactivate()
{
	_activated = false;
	for (uint32_t p = 0; p < num_ports(); ++p) {
		PortImpl* const port = _ports->at(p);
		port->deactivate();
	}
}

bool
BlockImpl::prepare_poly(BufferFactory& bufs, uint32_t poly)
{
	ThreadManager::assert_thread(THREAD_PRE_PROCESS);

	if (!_polyphonic)
		poly = 1;

	if (_ports)
		for (uint32_t i = 0; i < _ports->size(); ++i)
			_ports->at(i)->prepare_poly(bufs, poly);

	return true;
}

bool
BlockImpl::apply_poly(ProcessContext& context, Raul::Maid& maid, uint32_t poly)
{
	if (!_polyphonic)
		poly = 1;

	_polyphony = poly;

	if (_ports)
		for (uint32_t i = 0; i < num_ports(); ++i)
			_ports->at(i)->apply_poly(context, maid, poly);

	return true;
}

void
BlockImpl::set_buffer_size(Context&       context,
                           BufferFactory& bufs,
                           LV2_URID       type,
                           uint32_t       size)
{
	if (_ports) {
		for (uint32_t i = 0; i < _ports->size(); ++i) {
			PortImpl* const p = _ports->at(i);
			if (p->buffer_type() == type) {
				p->set_buffer_size(context, bufs, size);
			}
		}
	}
}

PortImpl*
BlockImpl::nth_port_by_type(uint32_t n, bool input, PortType type)
{
	uint32_t count = 0;
	for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
		PortImpl* const port = _ports->at(i);
		if (port->is_input() == input && port->type() == type) {
			if (count++ == n) {
				return port;
			}
		}
	}
	return NULL;
}

PortImpl*
BlockImpl::port_by_symbol(const char* symbol)
{
	for (uint32_t p = 0; _ports && p < _ports->size(); ++p) {
		if (_ports->at(p)->symbol() == symbol) {
			return _ports->at(p);
		}
	}
	return NULL;
}

void
BlockImpl::pre_process(ProcessContext& context)
{
	// Mix down input ports
	for (uint32_t i = 0; i < num_ports(); ++i) {
		PortImpl* const port = _ports->at(i);
		port->pre_process(context);
		port->connect_buffers();
	}
}

void
BlockImpl::process(ProcessContext& context)
{
	pre_process(context);

	if (!_enabled) {
		// Dumb bypass
		for (PortType t : { PortType::AUDIO, PortType::CV, PortType::ATOM }) {
			for (uint32_t i = 0;; ++i) {
				PortImpl* in  = nth_port_by_type(i, true, t);
				PortImpl* out = nth_port_by_type(i, false, t);
				if (!out) {
					break;  // Finished writing all outputs
				} else if (in) {
					// Copy corresponding input to output
					for (uint32_t v = 0; v < _polyphony; ++v) {
						out->buffer(v)->copy(context, in->buffer(v).get());
					}
				} else {
					// Output but no corresponding input, clear
					for (uint32_t v = 0; v < _polyphony; ++v) {
						out->buffer(v)->clear();
					}
				}
			}
		}
		post_process(context);
		return;
	}

	ProcessContext subcontext(context);
	for (SampleCount offset = 0; offset < context.nframes();) {
		// Find earliest offset of a value change
		SampleCount chunk_end = context.nframes();
		for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
			PortImpl* const port = _ports->at(i);
			if (port->type() == PortType::CONTROL && port->is_input()) {
				const SampleCount o = port->next_value_offset(
					offset, context.nframes());
				if (o < chunk_end) {
					chunk_end = o;
				}
			}
		}

		// Slice context into a chunk from now until the next change
		subcontext.slice(offset, chunk_end - offset);

		// Prepare port buffers for reading, converting/mixing if necessary
		for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
			_ports->at(i)->connect_buffers(offset);
			_ports->at(i)->pre_run(subcontext);
		}

		// Run the chunk
		run(subcontext);

		offset = chunk_end;
		subcontext.slice(offset, chunk_end - offset);
	}

	post_process(context);
}

void
BlockImpl::post_process(ProcessContext& context)
{
	// Write output ports
	for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
		_ports->at(i)->post_process(context);
	}
}

void
BlockImpl::set_port_buffer(uint32_t    voice,
                           uint32_t    port_num,
                           BufferRef   buf,
                           SampleCount offset)
{
	/*std::cout << path() << " set port " << port_num << " voice " << voice
	  << " buffer " << buf << " offset " << offset << std::endl;*/
}

} // namespace Server
} // namespace Ingen
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2013 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * 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.
 *
 */
#include <string.h>
#include <libsoup/soup.h>
#include "KmsHttpPost.h"

#define OBJECT_NAME "HttpPost"
#define MIME_MULTIPART_FORM_DATA "multipart/form-data"

#define GST_CAT_DEFAULT kms_http_post_debug_category
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

#define KMS_HTTP_POST_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KMS_TYPE_HTTP_POST, KmsHttpPostPrivate))

typedef enum {
  MULTIPART_FIND_BOUNDARY,
  MULTIPART_READ_HEADERS,
  MULTIPART_READ_CONTENT
} ParseState;

typedef struct _KmsHttpPostMultipart {
  gchar *boundary;
  ParseState state;
  gchar *tmp_buff;
  guint len;
} KmsHttpPostMultipart;

struct _KmsHttpPostPrivate {
  KmsHttpPostMultipart *multipart;
  SoupMessage *msg;
  gulong handler_id;
};

/* class initialization */

G_DEFINE_TYPE_WITH_CODE (KmsHttpPost, kms_http_post,
                         G_TYPE_OBJECT,
                         GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, OBJECT_NAME,
                             0, "debug category for " OBJECT_NAME " element") )
/* properties */
enum {
  PROP_0,

  PROP_MESSAGE,
  N_PROPERTIES
};

#define KMS_HTTP_PORT_DEFAULT_MESSAGE NULL

static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };

/* signals */
enum {
  GOT_DATA,
  LAST_SIGNAL
};

static guint obj_signals[LAST_SIGNAL] = { 0 };

static void
kms_http_post_concat_previous_buffer (KmsHttpPost *self, const char **start,
                                      const char **end)
{
  if (self->priv->multipart->tmp_buff == NULL)
    return;

  if (self->priv->multipart->tmp_buff <= *start &&
      *start <= self->priv->multipart->tmp_buff + self->priv->multipart->len) {
    /* Memory overlap => Do not reallocate more memory in this case */
    return;
  }

  self->priv->multipart->tmp_buff = (char *) g_realloc (
                                      self->priv->multipart->tmp_buff,
                                      self->priv->multipart->len + (*end - *start) );
  memmove (self->priv->multipart->tmp_buff + self->priv->multipart->len,
           *start, *end - *start);
  self->priv->multipart->len += (*end - *start);

  *start = self->priv->multipart->tmp_buff;
  *end = self->priv->multipart->tmp_buff + self->priv->multipart->len;
}

static void
kms_http_post_find_boundary (KmsHttpPost *self, const char **start,
                             const char **end, const char *boundary, int boundary_len)
{
  const char *b;

  if (self->priv->multipart->tmp_buff != NULL)
    kms_http_post_concat_previous_buffer (self, start, end);

  for (b = (const char *) memchr (*start, '-', *end - *start); b != NULL;
       b = (const char *) memchr (b + 2, '-', *end - (b + 2) ) ) {

    if (b + boundary_len + 4 > *end) {
      /* boundary does not fit in this buffer */
      gchar *mem = NULL;

      if (self->priv->multipart->tmp_buff != NULL)
        mem = self->priv->multipart->tmp_buff;

      self->priv->multipart->tmp_buff = (gchar *) g_memdup (b, *end - b);
      self->priv->multipart->len = *end - b;

      if (mem != NULL)
        g_free (mem);

      return;
    }

    /* Check for "--boundary" */
    if (b[1] != '-' ||
        memcmp (b + 2, boundary, boundary_len) != 0)
      continue;

    /* Check for "--" or "\r\n" after boundary */
    if ( (b[boundary_len + 2] == '-' && b[boundary_len + 3] == '-') ||
         (b[boundary_len + 2] == '\r' && b[boundary_len + 3] == '\n') ) {
      self->priv->multipart->state = MULTIPART_READ_HEADERS;

      if (*end <= b + boundary_len + 4) {
        /* Free temporal buffer */
        break;
      }

      *start = b + boundary_len + 4;
      return;
    }
  }

  if (self->priv->multipart->tmp_buff != NULL) {
    g_free (self->priv->multipart->tmp_buff);
    self->priv->multipart->tmp_buff = NULL;
  }
}

static void
kms_http_post_parse_header (KmsHttpPost *self, const char *start,
                            const char *end)
{
  gchar *header;

  header = strndup (start, end - start);
  GST_DEBUG ("TODO Parse header: *%s*", header);
  g_free (header);
}

static void
kms_http_post_read_headers (KmsHttpPost *self, const char **start,
                            const char **end)
{
  const char *b;

  if (self->priv->multipart->tmp_buff != NULL)
    kms_http_post_concat_previous_buffer (self, start, end);

  b = *start;

  while (b <= *end) {
    const char *newline = (const char *) memchr (b, '\n', *end - b);

    if (newline == NULL) {
      /* header does not fit in this buffer */
      gchar *mem = NULL;

      if (self->priv->multipart->tmp_buff != NULL)
        mem = self->priv->multipart->tmp_buff;

      self->priv->multipart->tmp_buff = (gchar *) g_memdup (b, *end - b);
      self->priv->multipart->len = *end - b;

      if (mem != NULL)
        g_free (mem);

      return;
    }

    /* Check if this is a blank line */
    if (newline - b == 1 && b[0] == '\r' && b[1] == '\n') {
      self->priv->multipart->state = MULTIPART_READ_CONTENT;

      if (*end <= newline + 1) {
        /* Free temporal buffer */
        break;
      }

      *start = newline + 1;
      return;
    }

    kms_http_post_parse_header (self, b, newline);

    /* Search next header starting from the next character following '\n' */
    b = newline + 1;
  }

  if (self->priv->multipart->tmp_buff != NULL) {
    g_free (self->priv->multipart->tmp_buff);
    self->priv->multipart->tmp_buff = NULL;
  }
}

static void
kms_http_post_parse_multipart_data (KmsHttpPost *self, const char *data,
                                    const char *end)
{
  switch (self->priv->multipart->state) {
  case MULTIPART_FIND_BOUNDARY:
    /* skip preamble */
    kms_http_post_find_boundary (self, &data, &end,
                                 self->priv->multipart->boundary,
                                 strlen (self->priv->multipart->boundary) );

    if (self->priv->multipart->state == MULTIPART_FIND_BOUNDARY)
      break;

  case MULTIPART_READ_HEADERS:
    kms_http_post_read_headers (self, &data, &end);

    if (self->priv->multipart->state == MULTIPART_READ_HEADERS)
      break;

  case MULTIPART_READ_CONTENT:
    GST_DEBUG ("TODO: Read content");
  }
}

static void
got_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
{
  KmsHttpPost *self = KMS_HTTP_POST (data);

  if (self->priv->multipart == NULL)
    GST_DEBUG ("Process raw data");
  else
    kms_http_post_parse_multipart_data (self, chunk->data,
                                        chunk->data + chunk->length);
}

static void
kms_http_post_destroy_multipart (KmsHttpPost *self)
{
  if (self->priv->multipart == NULL)
    return;

  if (self->priv->multipart->boundary != NULL)
    g_free (self->priv->multipart->boundary);

  if (self->priv->multipart->tmp_buff != NULL)
    g_free (self->priv->multipart->tmp_buff);

  g_slice_free (KmsHttpPostMultipart, self->priv->multipart);
  self->priv->multipart = NULL;
}

static void
kms_http_post_init_multipart (KmsHttpPost *self)
{
  if (self->priv->multipart != NULL) {
    GST_WARNING ("Multipart data is already initialized");
    kms_http_post_destroy_multipart (self);
  }

  self->priv->multipart = g_slice_new0 (KmsHttpPostMultipart);
}

static void
kms_http_post_configure_msg (KmsHttpPost *self)
{
  const gchar *content_type;
  GHashTable *params = NULL;

  content_type =
    soup_message_headers_get_content_type (self->priv->msg->request_headers,
        &params);

  if (content_type == NULL) {
    GST_WARNING ("Content-type header is not present in request");
    soup_message_set_status (self->priv->msg, SOUP_STATUS_NOT_ACCEPTABLE);
    goto end;
  }

  if (strncmp (content_type, "multipart/", 10) == 0) {
    if (strlen (content_type) >= 19 &&
        strncmp (content_type + 11, "form-data", 9) ) {
      /* Content-Type: multipart/form-data */
      kms_http_post_init_multipart (self);
      self->priv->multipart->boundary =
        g_strdup ( (gchar *) g_hash_table_lookup (params, "boundary") );

      if (self->priv->multipart->boundary == NULL) {
        GST_WARNING ("Malformed multipart POST request");
        kms_http_post_destroy_multipart (self);
        soup_message_set_status (self->priv->msg, SOUP_STATUS_NOT_ACCEPTABLE);
        goto end;
      }
    } else {
      GST_WARNING ("Unsupported multipart format: %s", content_type);
      soup_message_set_status (self->priv->msg, SOUP_STATUS_NOT_ACCEPTABLE);
      goto end;
    }
  }

  soup_message_set_status (self->priv->msg, SOUP_STATUS_OK);

  /* Get chunks without filling-in body's data field after */
  /* the body is fully sent/received */
  soup_message_body_set_accumulate (self->priv->msg->request_body, FALSE);

  self->priv->handler_id = g_signal_connect (self->priv->msg, "got-chunk",
                           G_CALLBACK (got_chunk_cb), self);
end:

  if (params != NULL)
    g_hash_table_destroy (params);
}

static void
kms_http_post_release_message (KmsHttpPost *self)
{
  if (self->priv->msg == NULL)
    return;

  if (self->priv->handler_id != 0L) {
    g_signal_handler_disconnect (self->priv->msg, self->priv->handler_id);
    self->priv->handler_id = 0L;
  }

  g_object_unref (self->priv->msg);
  self->priv->msg = NULL;
}

static void
kms_http_post_set_property (GObject *obj, guint prop_id,
                            const GValue *value, GParamSpec *pspec)
{
  KmsHttpPost *self = KMS_HTTP_POST (obj);

  switch (prop_id) {
  case PROP_MESSAGE:
    kms_http_post_release_message (self);
    kms_http_post_destroy_multipart (self);
    self->priv->msg = SOUP_MESSAGE (g_object_ref (g_value_get_object (value) ) );
    kms_http_post_configure_msg (self);
    break;

  default:
    /* We don't have any other property... */
    G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
    break;
  }
}

static void
kms_http_post_get_property (GObject *obj, guint prop_id, GValue *value,
                            GParamSpec *pspec)
{
  KmsHttpPost *self = KMS_HTTP_POST (obj);

  switch (prop_id) {
  case PROP_MESSAGE:
    g_value_set_object (value, self->priv->msg);
    break;

  default:
    /* We don't have any other property... */
    G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
    break;
  }
}

static void
kms_http_post_dispose (GObject *obj)
{
  KmsHttpPost *self = KMS_HTTP_POST (obj);

  kms_http_post_release_message (self);

  /* Chain up to the parent class */
  G_OBJECT_CLASS (kms_http_post_parent_class)->dispose (obj);
}

static void
kms_http_post_finalize (GObject *obj)
{
  KmsHttpPost *self = KMS_HTTP_POST (obj);

  kms_http_post_destroy_multipart (self);

  /* Chain up to the parent class */
  G_OBJECT_CLASS (kms_http_post_parent_class)->finalize (obj);
}

static void
kms_http_post_class_init (KmsHttpPostClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->set_property = kms_http_post_set_property;
  gobject_class->get_property = kms_http_post_get_property;
  gobject_class->dispose = kms_http_post_dispose;
  gobject_class->finalize = kms_http_post_finalize;

  obj_properties[PROP_MESSAGE] =
    g_param_spec_object ("soup-message",
                         "Soup message object",
                         "Message to get data from",
                         SOUP_TYPE_MESSAGE,
                         (GParamFlags) (G_PARAM_READWRITE) );

  g_object_class_install_properties (gobject_class,
                                     N_PROPERTIES,
                                     obj_properties);

  obj_signals[GOT_DATA] =
    g_signal_new ("got-data",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (KmsHttpPostClass, got_data), NULL, NULL,
                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);

  /* Registers a private structure for an instantiatable type */
  g_type_class_add_private (klass, sizeof (KmsHttpPostPrivate) );
}

static void
kms_http_post_init (KmsHttpPost *self)
{
  self->priv = KMS_HTTP_POST_GET_PRIVATE (self);
  self->priv->handler_id = 0L;
}<commit_msg>KmsHttpPost: Parse headers contained in multipart bodies<commit_after>/*
 * (C) Copyright 2013 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * 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.
 *
 */
#include <string.h>
#include <libsoup/soup.h>
#include "KmsHttpPost.h"

#define OBJECT_NAME "HttpPost"
#define MIME_MULTIPART_FORM_DATA "multipart/form-data"

#define GST_CAT_DEFAULT kms_http_post_debug_category
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

#define KMS_HTTP_POST_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KMS_TYPE_HTTP_POST, KmsHttpPostPrivate))

typedef enum {
  MULTIPART_FIND_BOUNDARY,
  MULTIPART_READ_HEADERS,
  MULTIPART_READ_CONTENT
} ParseState;

typedef struct _KmsHttpPostMultipart {
  SoupMessageHeaders *headers;
  gchar *boundary;
  ParseState state;
  gchar *tmp_buff;
  guint len;
} KmsHttpPostMultipart;

struct _KmsHttpPostPrivate {
  KmsHttpPostMultipart *multipart;
  SoupMessage *msg;
  gulong handler_id;
};

/* class initialization */

G_DEFINE_TYPE_WITH_CODE (KmsHttpPost, kms_http_post,
                         G_TYPE_OBJECT,
                         GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, OBJECT_NAME,
                             0, "debug category for " OBJECT_NAME " element") )
/* properties */
enum {
  PROP_0,

  PROP_MESSAGE,
  N_PROPERTIES
};

#define KMS_HTTP_PORT_DEFAULT_MESSAGE NULL

static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };

/* signals */
enum {
  GOT_DATA,
  LAST_SIGNAL
};

static guint obj_signals[LAST_SIGNAL] = { 0 };

static void
kms_http_post_concat_previous_buffer (KmsHttpPost *self, const char **start,
                                      const char **end)
{
  if (self->priv->multipart->tmp_buff == NULL)
    return;

  if (self->priv->multipart->tmp_buff <= *start &&
      *start <= self->priv->multipart->tmp_buff + self->priv->multipart->len) {
    /* Memory overlap => Do not reallocate more memory in this case */
    return;
  }

  self->priv->multipart->tmp_buff = (char *) g_realloc (
                                      self->priv->multipart->tmp_buff,
                                      self->priv->multipart->len + (*end - *start) );
  memmove (self->priv->multipart->tmp_buff + self->priv->multipart->len,
           *start, *end - *start);
  self->priv->multipart->len += (*end - *start);

  *start = self->priv->multipart->tmp_buff;
  *end = self->priv->multipart->tmp_buff + self->priv->multipart->len;
}

static void
kms_http_post_find_boundary (KmsHttpPost *self, const char **start,
                             const char **end, const char *boundary, int boundary_len)
{
  const char *b;

  if (self->priv->multipart->tmp_buff != NULL)
    kms_http_post_concat_previous_buffer (self, start, end);

  for (b = (const char *) memchr (*start, '-', *end - *start); b != NULL;
       b = (const char *) memchr (b + 2, '-', *end - (b + 2) ) ) {

    if (b + boundary_len + 4 > *end) {
      /* boundary does not fit in this buffer */
      gchar *mem = NULL;

      if (self->priv->multipart->tmp_buff != NULL)
        mem = self->priv->multipart->tmp_buff;

      self->priv->multipart->tmp_buff = (gchar *) g_memdup (b, *end - b);
      self->priv->multipart->len = *end - b;

      if (mem != NULL)
        g_free (mem);

      return;
    }

    /* Check for "--boundary" */
    if (b[1] != '-' ||
        memcmp (b + 2, boundary, boundary_len) != 0)
      continue;

    /* Check for "--" or "\r\n" after boundary */
    if ( (b[boundary_len + 2] == '-' && b[boundary_len + 3] == '-') ||
         (b[boundary_len + 2] == '\r' && b[boundary_len + 3] == '\n') ) {
      self->priv->multipart->state = MULTIPART_READ_HEADERS;

      if (*end <= b + boundary_len + 4) {
        /* Free temporal buffer */
        break;
      }

      *start = b + boundary_len + 4;
      return;
    }
  }

  if (self->priv->multipart->tmp_buff != NULL) {
    g_free (self->priv->multipart->tmp_buff);
    self->priv->multipart->tmp_buff = NULL;
  }
}

static void
kms_http_post_parse_header (KmsHttpPost *self, const char *start,
                            const char *end)
{
  const char *name_start, *name_end, *value_start, *value_end, *eol;
  char *name, *value;

  name_start = start;
  name_end = strchr (start, ':');

  /* Reject if there is no ':', or the header name is
   * empty, or it contains whitespace.
   */
  if (name_end == NULL || name_end == name_start ||
      name_start + strcspn (name_start, " \t\r\n") < name_end) {
    /* Ignore this line. */
    return;
  }

  /* Find the end of the value; ie, an end-of-line that
   * isn't followed by a continuation line.
   */
  value_start = name_end + 1;
  value_end = strchr (name_start, '\n');

  if (value_end == NULL)
    return;

  /* Skip leading whitespace */
  while (value_start < value_end &&
         (*value_start == ' ' || *value_start == '\t' ||
          *value_start == '\r' || *value_start == '\n') )
    value_start++;

  /* clip trailing whitespace */
  eol = value_end;

  while (eol > value_start &&
         (eol[-1] == ' ' || eol[-1] == '\t' || eol[-1] == '\r') )
    eol--;

  name = g_strndup (name_start, name_end - name_start );
  value = g_strndup (value_start, eol - value_start );

  /* Add new header */
  soup_message_headers_append (self->priv->multipart->headers, name, value);

  g_free (name);
  g_free (value);
}

static void
kms_http_post_read_headers (KmsHttpPost *self, const char **start,
                            const char **end)
{
  const char *b;

  if (self->priv->multipart->tmp_buff != NULL)
    kms_http_post_concat_previous_buffer (self, start, end);

  b = *start;

  while (b <= *end) {
    const char *newline = (const char *) memchr (b, '\n', *end - b);

    if (newline == NULL) {
      /* header does not fit in this buffer */
      gchar *mem = NULL;

      if (self->priv->multipart->tmp_buff != NULL)
        mem = self->priv->multipart->tmp_buff;

      self->priv->multipart->tmp_buff = (gchar *) g_memdup (b, *end - b);
      self->priv->multipart->len = *end - b;

      if (mem != NULL)
        g_free (mem);

      return;
    }

    /* Check if this is a blank line */
    if (newline - b == 1 && b[0] == '\r' && b[1] == '\n') {
      self->priv->multipart->state = MULTIPART_READ_CONTENT;

      if (*end <= newline + 1) {
        /* Free temporal buffer */
        break;
      }

      *start = newline + 1;
      return;
    }

    kms_http_post_parse_header (self, b, newline);

    /* Search next header starting from the next character following '\n' */
    b = newline + 1;
  }

  if (self->priv->multipart->tmp_buff != NULL) {
    g_free (self->priv->multipart->tmp_buff);
    self->priv->multipart->tmp_buff = NULL;
  }
}

static void
kms_http_post_parse_multipart_data (KmsHttpPost *self, const char *data,
                                    const char *end)
{
  switch (self->priv->multipart->state) {
  case MULTIPART_FIND_BOUNDARY:
    /* skip preamble */
    kms_http_post_find_boundary (self, &data, &end,
                                 self->priv->multipart->boundary,
                                 strlen (self->priv->multipart->boundary) );

    if (self->priv->multipart->state == MULTIPART_FIND_BOUNDARY)
      break;

  case MULTIPART_READ_HEADERS:
    kms_http_post_read_headers (self, &data, &end);

    if (self->priv->multipart->state == MULTIPART_READ_HEADERS)
      break;

  case MULTIPART_READ_CONTENT:
    GST_DEBUG ("TODO: Read content");
  }
}

static void
got_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
{
  KmsHttpPost *self = KMS_HTTP_POST (data);

  if (self->priv->multipart == NULL)
    GST_DEBUG ("Process raw data");
  else
    kms_http_post_parse_multipart_data (self, chunk->data,
                                        chunk->data + chunk->length);
}

static void
kms_http_post_destroy_multipart (KmsHttpPost *self)
{
  if (self->priv->multipart == NULL)
    return;

  if (self->priv->multipart->boundary != NULL)
    g_free (self->priv->multipart->boundary);

  if (self->priv->multipart->headers != NULL)
    soup_message_headers_free (self->priv->multipart->headers);

  if (self->priv->multipart->tmp_buff != NULL)
    g_free (self->priv->multipart->tmp_buff);

  g_slice_free (KmsHttpPostMultipart, self->priv->multipart);
  self->priv->multipart = NULL;
}

static void
kms_http_post_init_multipart (KmsHttpPost *self)
{
  if (self->priv->multipart != NULL) {
    GST_WARNING ("Multipart data is already initialized");
    kms_http_post_destroy_multipart (self);
  }

  self->priv->multipart = g_slice_new0 (KmsHttpPostMultipart);
  self->priv->multipart->headers =
    soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
}

static void
kms_http_post_configure_msg (KmsHttpPost *self)
{
  const gchar *content_type;
  GHashTable *params = NULL;

  content_type =
    soup_message_headers_get_content_type (self->priv->msg->request_headers,
        &params);

  if (content_type == NULL) {
    GST_WARNING ("Content-type header is not present in request");
    soup_message_set_status (self->priv->msg, SOUP_STATUS_NOT_ACCEPTABLE);
    goto end;
  }

  if (strncmp (content_type, "multipart/", 10) == 0) {
    if (strlen (content_type) >= 19 &&
        strncmp (content_type + 11, "form-data", 9) ) {
      /* Content-Type: multipart/form-data */
      kms_http_post_init_multipart (self);
      self->priv->multipart->boundary =
        g_strdup ( (gchar *) g_hash_table_lookup (params, "boundary") );

      if (self->priv->multipart->boundary == NULL) {
        GST_WARNING ("Malformed multipart POST request");
        kms_http_post_destroy_multipart (self);
        soup_message_set_status (self->priv->msg, SOUP_STATUS_NOT_ACCEPTABLE);
        goto end;
      }
    } else {
      GST_WARNING ("Unsupported multipart format: %s", content_type);
      soup_message_set_status (self->priv->msg, SOUP_STATUS_NOT_ACCEPTABLE);
      goto end;
    }
  }

  soup_message_set_status (self->priv->msg, SOUP_STATUS_OK);

  /* Get chunks without filling-in body's data field after */
  /* the body is fully sent/received */
  soup_message_body_set_accumulate (self->priv->msg->request_body, FALSE);

  self->priv->handler_id = g_signal_connect (self->priv->msg, "got-chunk",
                           G_CALLBACK (got_chunk_cb), self);
end:

  if (params != NULL)
    g_hash_table_destroy (params);
}

static void
kms_http_post_release_message (KmsHttpPost *self)
{
  if (self->priv->msg == NULL)
    return;

  if (self->priv->handler_id != 0L) {
    g_signal_handler_disconnect (self->priv->msg, self->priv->handler_id);
    self->priv->handler_id = 0L;
  }

  g_object_unref (self->priv->msg);
  self->priv->msg = NULL;
}

static void
kms_http_post_set_property (GObject *obj, guint prop_id,
                            const GValue *value, GParamSpec *pspec)
{
  KmsHttpPost *self = KMS_HTTP_POST (obj);

  switch (prop_id) {
  case PROP_MESSAGE:
    kms_http_post_release_message (self);
    kms_http_post_destroy_multipart (self);
    self->priv->msg = SOUP_MESSAGE (g_object_ref (g_value_get_object (value) ) );
    kms_http_post_configure_msg (self);
    break;

  default:
    /* We don't have any other property... */
    G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
    break;
  }
}

static void
kms_http_post_get_property (GObject *obj, guint prop_id, GValue *value,
                            GParamSpec *pspec)
{
  KmsHttpPost *self = KMS_HTTP_POST (obj);

  switch (prop_id) {
  case PROP_MESSAGE:
    g_value_set_object (value, self->priv->msg);
    break;

  default:
    /* We don't have any other property... */
    G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
    break;
  }
}

static void
kms_http_post_dispose (GObject *obj)
{
  KmsHttpPost *self = KMS_HTTP_POST (obj);

  kms_http_post_release_message (self);

  /* Chain up to the parent class */
  G_OBJECT_CLASS (kms_http_post_parent_class)->dispose (obj);
}

static void
kms_http_post_finalize (GObject *obj)
{
  KmsHttpPost *self = KMS_HTTP_POST (obj);

  kms_http_post_destroy_multipart (self);

  /* Chain up to the parent class */
  G_OBJECT_CLASS (kms_http_post_parent_class)->finalize (obj);
}

static void
kms_http_post_class_init (KmsHttpPostClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->set_property = kms_http_post_set_property;
  gobject_class->get_property = kms_http_post_get_property;
  gobject_class->dispose = kms_http_post_dispose;
  gobject_class->finalize = kms_http_post_finalize;

  obj_properties[PROP_MESSAGE] =
    g_param_spec_object ("soup-message",
                         "Soup message object",
                         "Message to get data from",
                         SOUP_TYPE_MESSAGE,
                         (GParamFlags) (G_PARAM_READWRITE) );

  g_object_class_install_properties (gobject_class,
                                     N_PROPERTIES,
                                     obj_properties);

  obj_signals[GOT_DATA] =
    g_signal_new ("got-data",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (KmsHttpPostClass, got_data), NULL, NULL,
                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);

  /* Registers a private structure for an instantiatable type */
  g_type_class_add_private (klass, sizeof (KmsHttpPostPrivate) );
}

static void
kms_http_post_init (KmsHttpPost *self)
{
  self->priv = KMS_HTTP_POST_GET_PRIVATE (self);
  self->priv->handler_id = 0L;
}<|endoftext|>


<commit_before>#include "ChimericAlign.h"

ChimericAlign::ChimericAlign(ChimericSegment &seg1in, ChimericSegment &seg2in, int chimScoreIn, vector <Transcript> &vecAlignsIn)
                              : seg1(seg1in), seg2(seg2in),chimScore(chimScoreIn), vecAligns(vecAlignsIn), P(seg1in.P), pCh(P.pCh)
{
    stitchingDone=false;

    al1=&seg1.align;
    al2=&seg2.align;

    if (al1->roStart > al2->roStart)
        swap (al1,al2);

    ex1 = al1->Str==1 ? 0 : al1->nExons-1;
    ex2 = al2->Str==0 ? 0 : al2->nExons-1;
};

bool ChimericAlign::chimericCheck()
{
    bool chimGood=true;

    chimGood = chimGood && al1->exons[ex1][EX_iFrag] <= al2->exons[ex2][EX_iFrag];//otherwise - strange configuration, both segments contain two mates
        //if ( trChim[0].exons[e0][EX_iFrag] > trChim[1].exons[e1][EX_iFrag] ) {//strange configuration, rare, similar to the next one
        //    chimN=0;//reject such chimeras
            //good test example:
            //CTTAGCTAGCAGCGTCTTCCCAGTGCCTGGAGGGCCAGTGAGAATGGCACCCTCTGGGATTTTTGCTCCTAGGTCT
            //TTGAGGTGAAGTTCAAAGATGTGGCTGGCTGTGAGGAGGCCGAGCTAGAGATCATGGAATTTGTGAATTTCTTGAA
        //} else

    chimGood = chimGood && al1->exons[ex1][EX_L] >= pCh.junctionOverhangMin &&  al2->exons[ex2][EX_L] >= pCh.junctionOverhangMin;//junction overhangs too short

    return chimGood;
};<commit_msg>Changed pre-filtering of short overhangs - only done for chimerically split mates. Result are slightly different from the previous commit.<commit_after>#include "ChimericAlign.h"

ChimericAlign::ChimericAlign(ChimericSegment &seg1in, ChimericSegment &seg2in, int chimScoreIn, vector <Transcript> &vecAlignsIn)
                              : seg1(seg1in), seg2(seg2in),chimScore(chimScoreIn), vecAligns(vecAlignsIn), P(seg1in.P), pCh(P.pCh)
{
    stitchingDone=false;

    al1=&seg1.align;
    al2=&seg2.align;

    if (al1->roStart > al2->roStart)
        swap (al1,al2);

    ex1 = al1->Str==1 ? 0 : al1->nExons-1;
    ex2 = al2->Str==0 ? 0 : al2->nExons-1;
};

bool ChimericAlign::chimericCheck()
{
    bool chimGood=true;

    chimGood = chimGood && al1->exons[ex1][EX_iFrag] <= al2->exons[ex2][EX_iFrag];//otherwise - strange configuration, both segments contain two mates
        //if ( trChim[0].exons[e0][EX_iFrag] > trChim[1].exons[e1][EX_iFrag] ) {//strange configuration, rare, similar to the next one
        //    chimN=0;//reject such chimeras
            //good test example:
            //CTTAGCTAGCAGCGTCTTCCCAGTGCCTGGAGGGCCAGTGAGAATGGCACCCTCTGGGATTTTTGCTCCTAGGTCT
            //TTGAGGTGAAGTTCAAAGATGTGGCTGGCTGTGAGGAGGCCGAGCTAGAGATCATGGAATTTGTGAATTTCTTGAA
        //} else

    //junction overhangs too short for chimerically spliced mates
    chimGood = chimGood && (al1->exons[ex1][EX_iFrag] < al2->exons[ex2][EX_iFrag] || (al1->exons[ex1][EX_L] >= pCh.junctionOverhangMin &&  al2->exons[ex2][EX_L] >= pCh.junctionOverhangMin) );

    return chimGood;
};
<|endoftext|>


<commit_before>#include <QPainter>
#include <QAbstractEventDispatcher>
#include <QApplication>
#include <QPaintEvent>
#include <QFontMetrics>
#include <QTextStream>
#include <qterm.h>
#include <stdio.h>
#include <QKeyEvent>
#include <QTimer>
#include <sys/select.h>
#include <errno.h>
#ifdef __QNX__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <bbsupport/Keyboard>
#include <bbsupport/Notification>
#endif

#define WIDTH    80
#define HEIGHT    17
#define BLINK_SPEED 1000

QTerm::QTerm(QWidget *parent) : QWidget(parent)
{
    term_create( &terminal );
    term_begin( terminal, WIDTH, HEIGHT, 0 );
    init();
}

QTerm::QTerm(QWidget *parent, term_t terminal) : QWidget(parent)
{
    this->terminal = terminal;
    init();
}

void QTerm::init()
{
    char_width = 0;
    char_height = 0;
    cursor_x = -1;
    cursor_y = -1;
    cursor_on = 1;

    resize(1024, 600);
    term_set_user_data( terminal, this );
    term_register_update( terminal, term_update );
    term_register_cursor( terminal, term_update_cursor );
    term_register_bell( terminal, term_bell );
    notifier = new QSocketNotifier( term_get_file_descriptor(terminal), QSocketNotifier::Read );
    exit_notifier = new QSocketNotifier( term_get_file_descriptor(terminal), QSocketNotifier::Exception );
    cursor_timer = new QTimer( this );
    QObject::connect(notifier, SIGNAL(activated(int)), this, SLOT(terminal_data()));
    QObject::connect(exit_notifier, SIGNAL(activated(int)), this, SLOT(terminate()));
    QObject::connect(cursor_timer, SIGNAL(timeout()), this, SLOT(blink_cursor()));

    // Setup the initial font
    font = new QFont();
    font->setStyleHint(QFont::Courier);//QFont::TypeWriter);
    font->setPointSize(12);
    font->setStyleStrategy(QFont::NoAntialias);
    font->setFamily("Monospace");
    font->setFixedPitch(true);
    font->setKerning(false);

    // Workaround for a bug in OSX - Dave reports that maxWidth returns 0,
    // when width of different characters returns the correct value
    QFontMetrics metrics(*font);
    char_width = metrics.maxWidth();
    if(char_width==0) {
        fontWorkAround = true;
        char_width = metrics.width(QChar('X'));
    } else {
        fontWorkAround = false;
    }

    char_height = metrics.lineSpacing();
    char_descent = metrics.descent();

#ifdef __QNX__
    BlackBerry::Keyboard::instance().show();
#endif
    cursor_timer->start(BLINK_SPEED);
}

QTerm::~QTerm()
{
    delete notifier;
    delete exit_notifier;
    term_free( terminal );
}

void QTerm::term_bell(term_t handle)
{
#ifdef __QNX__
    char command[] = "msg::play_sound\ndat:json:{\"sound\":\"notification_general\"}";
    int f = open("/pps/services/multimedia/sound/control", O_RDWR);
    write(f, command, sizeof(command));
    ::close(f);
#else
    QApplication::beep();
#endif
}

void QTerm::term_update(term_t handle, int x, int y, int width, int height)
{
    QTerm *term = (QTerm *)term_get_user_data( handle );

    term->update_grid(x, y, width, height);
}

void QTerm::term_update_cursor(term_t handle, int x, int y)
{
    QTerm *term = (QTerm *)term_get_user_data( handle );
    // Update old cursor location
    term->cursor_on = 0;
    term->update_grid( term->cursor_x, term->cursor_y, 1, 1);

    // TODO:  Should also reset the blink timer to have consistency.
    term->cursor_on = 1;
    term->cursor_x = x;
    term->cursor_y = y;

    term->update_grid( term->cursor_x, term->cursor_y, 1, 1);
}

void QTerm::terminal_data()
{
    if( !term_process_child( terminal ) ) {
        exit(0);
    }
}

void QTerm::terminate()
{
    exit(0);
}

void QTerm::blink_cursor()
{
    //int coord_x;
    cursor_on ^= 1;
    update_grid( cursor_x, cursor_y, 1, 1);
}

// Called to update the grid.
// Region is based on grid coordinates.
void QTerm::update_grid(int grid_x_min,
                        int grid_y_min,
                        int grid_width,
                        int grid_height)
{
    int coords_x_min, coords_y_min;
    int coords_x_max, coords_y_max;

//    fprintf(stderr,"Updating Grid: (%d,%d) %d x %d\n", grid_x_min, grid_y_min, grid_width, grid_height);

    if (grid_x_min < 0 || grid_y_min < 0) {
        return;
    }
    if ( fontWorkAround ) {
        // If fontWorkAround is set, we cannot trust the characters to
        // be monospaced.  So we need to calculate the coordinates based
        // on the string lengths of the strings in the grid.
        QFontMetrics metrics(*font);

        const char *str;
        int i;

        coords_x_min = 9999;    // Replace with some window property.
        coords_x_max = 0;
        for (i= grid_y_min; i < (grid_y_min + grid_height); i++) {
            int tmp;
            str = term_get_line( terminal, i );

            // X limits
            tmp = metrics.width(QString(str),grid_x_min);
            if (tmp < coords_x_min) {
                coords_x_min = tmp;
            }
            tmp = metrics.width(QString(str),grid_x_min + grid_width);
            if (tmp > coords_x_max) {
                coords_x_max = tmp;
            }
        }

    } else {
        coords_x_min = grid_x_min * char_width;
        coords_x_max = grid_width * char_width;
    }
    coords_y_min = grid_y_min * char_height;
    coords_y_max = grid_height * char_height;
    QWidget::update(coords_x_min, coords_y_min,
                    coords_x_max, coords_y_max);
}
void QTerm::paintEvent(QPaintEvent *event)
{
    int i;
#if 0
    int color;
    const wchar_t **grid;
    const uint32_t **attribs;
    const uint32_t **colors;
#endif
    QPainter painter(this);
    QRect windowRect = painter.window();
    const char *str;
    int cursor_x_coord;
    QColor fgColor(255,255,255);
    QColor bgColor(0,0,0);
    int gridWidth, gridHeight;

    painter.setBackgroundMode(Qt::TransparentMode);
    painter.setBrush(QColor(8, 0, 0));
    painter.setFont( *font );

    // Get grid dimensions
    term_get_grid_size(terminal, &gridWidth, &gridHeight);

    // First erase the grid with its current dimensions
    painter.drawRect(event->rect());

//    fprintf(stderr,"Rect: (%d, %d) %d x %d\n", event->rect().x(), event->rect().y(), event->rect().width(), event->rect().height());

    if (cursor_x < 0 || cursor_y < 0) {
        return;
    }

#if 1
    str = term_get_line( terminal, cursor_y );
    // Workaround to get the cursor in the right spot.  For some
    // reason, on OSX (again), the monospace font does is not really
    // monospace for skinny characters!
    if (fontWorkAround) {
        cursor_x_coord = painter.fontMetrics().width(QString(str),cursor_x);
    } else {
        cursor_x_coord = cursor_x * char_width;
    }

    if ( cursor_on ) {
       painter.setPen(fgColor);
       painter.setBrush(fgColor);
       painter.drawRect( cursor_x_coord +1,
                         cursor_y * char_height + 1,
                         char_width-2, char_height-2);
    } else {
       painter.setPen(bgColor);
       painter.setBrush(bgColor);
       painter.drawRect( cursor_x_coord +1,
                         cursor_y * char_height + 1,
                         char_width-2, char_height-2);
    }
    painter.setPen(fgColor);
    painter.setBrush(fgColor);

    for (i=0; i< gridHeight;i++) {
        str = term_get_line( terminal, i );
        painter.drawText(0, (i) * char_height,
                        windowRect.width(),char_height,
                        Qt::TextExpandTabs,
                        str,
                        &windowRect
                        );
    }

#else
    grid = term_get_grid( terminal );
    attribs = term_get_attribs( terminal );
    colors = term_get_colours( terminal );

    painter.setBrush(fgColor);
    for( i = 0; i < term_get_height( terminal ); i ++ ) {
        for( j = 0; j < term_get_width( terminal ); j ++ ) {
            if( cursor_on && j == cursor_x && i == cursor_y ) {
                painter.drawRect(j * char_width + 1, i * char_height + 1, char_width - 2, char_height - 2);
                painter.setPen(QColor(0, 0, 0));
                painter.drawText(j * char_width, (i + 1) * char_height - char_descent, QString( QChar( grid[ i ][ j ] ) ) );
                painter.setPen(QColor(255, 255, 255));
            } else {

                color = term_get_fg_color( attribs[ i ][ j ], colors[ i ][ j ] );
                painter.setPen(QColor((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF));
                painter.drawText(j * char_width, (i + 1) * char_height - char_descent, QString( QChar( grid[ i ][ j ] ) ) );
            }
        }
    }
#endif
}

void QTerm::keyPressEvent(QKeyEvent *event)
{
    switch(event->key()) {
        // FIXME These first two are a workaround for a bug in QT. Remove once it is fixed
        case Qt::Key_CapsLock:
        case Qt::Key_Shift:
            break;
        case Qt::Key_Up:
            term_send_special( terminal, TERM_KEY_UP );
            break;
        case Qt::Key_Down:
            term_send_special( terminal, TERM_KEY_DOWN );
            break;
        case Qt::Key_Right:
            term_send_special( terminal, TERM_KEY_RIGHT );
            break;
        case Qt::Key_Left:
            term_send_special( terminal, TERM_KEY_LEFT );
            break;
        default:
            term_send_data( terminal, event->text().toUtf8().constData(), event->text().count() );
            break;
    }
}

void QTerm::resizeEvent(QResizeEvent *event)
{
    if( char_width != 0 && char_height != 0 ) {
#ifdef __QNX__
        {
            int kbd_height;
            kbd_height = BlackBerry::Keyboard::instance().keyboardHeight();
            term_resize( terminal, event->size().width() / char_width, (event->size().height() - kbd_height) / char_height, 0 );
        }
#else
        term_resize( terminal, event->size().width() / char_width, event->size().height() / char_height, 0 );
#endif
    }
}

int main(int argc, char *argv[])
{
    term_t terminal;
    if( !term_create( &terminal ) ) {
        fprintf(stderr, "Failed to create terminal (%s)\n", strerror( errno ) );
        exit(1);
    }
    if( !term_begin( terminal, WIDTH, HEIGHT, 0 ) ) {
        fprintf(stderr, "Failed to begin terminal (%s)\n", strerror( errno ) );
        exit(1);
    }
    {
        QCoreApplication::addLibraryPath("app/native/lib");
        QApplication app(argc, argv);

        QTerm term(NULL, terminal);
        term.show();

        return app.exec();
    }
}
<commit_msg>Fix the cursor TODO that Dave left in :)<commit_after>#include <QPainter>
#include <QAbstractEventDispatcher>
#include <QApplication>
#include <QPaintEvent>
#include <QFontMetrics>
#include <QTextStream>
#include <qterm.h>
#include <stdio.h>
#include <QKeyEvent>
#include <QTimer>
#include <sys/select.h>
#include <errno.h>
#ifdef __QNX__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <bbsupport/Keyboard>
#include <bbsupport/Notification>
#endif

#define WIDTH    80
#define HEIGHT    17
#define BLINK_SPEED 1000

QTerm::QTerm(QWidget *parent) : QWidget(parent)
{
    term_create( &terminal );
    term_begin( terminal, WIDTH, HEIGHT, 0 );
    init();
}

QTerm::QTerm(QWidget *parent, term_t terminal) : QWidget(parent)
{
    this->terminal = terminal;
    init();
}

void QTerm::init()
{
    char_width = 0;
    char_height = 0;
    cursor_x = -1;
    cursor_y = -1;
    cursor_on = 1;

    resize(1024, 600);
    term_set_user_data( terminal, this );
    term_register_update( terminal, term_update );
    term_register_cursor( terminal, term_update_cursor );
    term_register_bell( terminal, term_bell );
    notifier = new QSocketNotifier( term_get_file_descriptor(terminal), QSocketNotifier::Read );
    exit_notifier = new QSocketNotifier( term_get_file_descriptor(terminal), QSocketNotifier::Exception );
    cursor_timer = new QTimer( this );
    QObject::connect(notifier, SIGNAL(activated(int)), this, SLOT(terminal_data()));
    QObject::connect(exit_notifier, SIGNAL(activated(int)), this, SLOT(terminate()));
    QObject::connect(cursor_timer, SIGNAL(timeout()), this, SLOT(blink_cursor()));

    // Setup the initial font
    font = new QFont();
    font->setStyleHint(QFont::Courier);//QFont::TypeWriter);
    font->setPointSize(12);
    font->setStyleStrategy(QFont::NoAntialias);
    font->setFamily("Monospace");
    font->setFixedPitch(true);
    font->setKerning(false);

    // Workaround for a bug in OSX - Dave reports that maxWidth returns 0,
    // when width of different characters returns the correct value
    QFontMetrics metrics(*font);
    char_width = metrics.maxWidth();
    if(char_width==0) {
        fontWorkAround = true;
        char_width = metrics.width(QChar('X'));
    } else {
        fontWorkAround = false;
    }

    char_height = metrics.lineSpacing();
    char_descent = metrics.descent();

#ifdef __QNX__
    BlackBerry::Keyboard::instance().show();
#endif
    cursor_timer->start(BLINK_SPEED);
}

QTerm::~QTerm()
{
    delete notifier;
    delete exit_notifier;
    term_free( terminal );
}

void QTerm::term_bell(term_t handle)
{
#ifdef __QNX__
    char command[] = "msg::play_sound\ndat:json:{\"sound\":\"notification_general\"}";
    int f = open("/pps/services/multimedia/sound/control", O_RDWR);
    write(f, command, sizeof(command));
    ::close(f);
#else
    QApplication::beep();
#endif
}

void QTerm::term_update(term_t handle, int x, int y, int width, int height)
{
    QTerm *term = (QTerm *)term_get_user_data( handle );

    term->update_grid(x, y, width, height);
}

void QTerm::term_update_cursor(term_t handle, int x, int y)
{
    int old_x, old_y;
    QTerm *term = (QTerm *)term_get_user_data( handle );

    old_x = term->cursor_x;
    old_y = term->cursor_y;

    // Reset cursor blink
    term->cursor_on = 1;
    term->cursor_timer->stop();
    term->cursor_timer->start(BLINK_SPEED);

    // Update position
    term->cursor_x = x;
    term->cursor_y = y;

    // Update old and new cursor location
    term->update_grid( old_x, old_y, 1, 1);
    term->update_grid( term->cursor_x, term->cursor_y, 1, 1);
}

void QTerm::terminal_data()
{
    if( !term_process_child( terminal ) ) {
        exit(0);
    }
}

void QTerm::terminate()
{
    exit(0);
}

void QTerm::blink_cursor()
{
    //int coord_x;
    cursor_on ^= 1;
    update_grid( cursor_x, cursor_y, 1, 1);
}

// Called to update the grid.
// Region is based on grid coordinates.
void QTerm::update_grid(int grid_x_min,
                        int grid_y_min,
                        int grid_width,
                        int grid_height)
{
    int coords_x_min, coords_y_min;
    int coords_x_max, coords_y_max;

//    fprintf(stderr,"Updating Grid: (%d,%d) %d x %d\n", grid_x_min, grid_y_min, grid_width, grid_height);

    if (grid_x_min < 0 || grid_y_min < 0) {
        return;
    }
    if ( fontWorkAround ) {
        // If fontWorkAround is set, we cannot trust the characters to
        // be monospaced.  So we need to calculate the coordinates based
        // on the string lengths of the strings in the grid.
        QFontMetrics metrics(*font);

        const char *str;
        int i;

        coords_x_min = 9999;    // Replace with some window property.
        coords_x_max = 0;
        for (i= grid_y_min; i < (grid_y_min + grid_height); i++) {
            int tmp;
            str = term_get_line( terminal, i );

            // X limits
            tmp = metrics.width(QString(str),grid_x_min);
            if (tmp < coords_x_min) {
                coords_x_min = tmp;
            }
            tmp = metrics.width(QString(str),grid_x_min + grid_width);
            if (tmp > coords_x_max) {
                coords_x_max = tmp;
            }
        }

    } else {
        coords_x_min = grid_x_min * char_width;
        coords_x_max = grid_width * char_width;
    }
    coords_y_min = grid_y_min * char_height;
    coords_y_max = grid_height * char_height;
    QWidget::update(coords_x_min, coords_y_min,
                    coords_x_max, coords_y_max);
}
void QTerm::paintEvent(QPaintEvent *event)
{
    int i;
#if 0
    int color;
    const wchar_t **grid;
    const uint32_t **attribs;
    const uint32_t **colors;
#endif
    QPainter painter(this);
    QRect windowRect = painter.window();
    const char *str;
    int cursor_x_coord;
    QColor fgColor(255,255,255);
    QColor bgColor(0,0,0);
    int gridWidth, gridHeight;

    painter.setBackgroundMode(Qt::TransparentMode);
    painter.setBrush(QColor(8, 0, 0));
    painter.setFont( *font );

    // Get grid dimensions
    term_get_grid_size(terminal, &gridWidth, &gridHeight);

    // First erase the grid with its current dimensions
    painter.drawRect(event->rect());

//    fprintf(stderr,"Rect: (%d, %d) %d x %d\n", event->rect().x(), event->rect().y(), event->rect().width(), event->rect().height());

    if (cursor_x < 0 || cursor_y < 0) {
        return;
    }

#if 1
    str = term_get_line( terminal, cursor_y );
    // Workaround to get the cursor in the right spot.  For some
    // reason, on OSX (again), the monospace font does is not really
    // monospace for skinny characters!
    if (fontWorkAround) {
        cursor_x_coord = painter.fontMetrics().width(QString(str),cursor_x);
    } else {
        cursor_x_coord = cursor_x * char_width;
    }

    if ( cursor_on ) {
       painter.setPen(fgColor);
       painter.setBrush(fgColor);
       painter.drawRect( cursor_x_coord +1,
                         cursor_y * char_height + 1,
                         char_width-2, char_height-2);
    } else {
       painter.setPen(bgColor);
       painter.setBrush(bgColor);
       painter.drawRect( cursor_x_coord +1,
                         cursor_y * char_height + 1,
                         char_width-2, char_height-2);
    }
    painter.setPen(fgColor);
    painter.setBrush(fgColor);

    for (i=0; i< gridHeight;i++) {
        str = term_get_line( terminal, i );
        painter.drawText(0, (i) * char_height,
                        windowRect.width(),char_height,
                        Qt::TextExpandTabs,
                        str,
                        &windowRect
                        );
    }

#else
    grid = term_get_grid( terminal );
    attribs = term_get_attribs( terminal );
    colors = term_get_colours( terminal );

    painter.setBrush(fgColor);
    for( i = 0; i < term_get_height( terminal ); i ++ ) {
        for( j = 0; j < term_get_width( terminal ); j ++ ) {
            if( cursor_on && j == cursor_x && i == cursor_y ) {
                painter.drawRect(j * char_width + 1, i * char_height + 1, char_width - 2, char_height - 2);
                painter.setPen(QColor(0, 0, 0));
                painter.drawText(j * char_width, (i + 1) * char_height - char_descent, QString( QChar( grid[ i ][ j ] ) ) );
                painter.setPen(QColor(255, 255, 255));
            } else {

                color = term_get_fg_color( attribs[ i ][ j ], colors[ i ][ j ] );
                painter.setPen(QColor((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF));
                painter.drawText(j * char_width, (i + 1) * char_height - char_descent, QString( QChar( grid[ i ][ j ] ) ) );
            }
        }
    }
#endif
}

void QTerm::keyPressEvent(QKeyEvent *event)
{
    switch(event->key()) {
        // FIXME These first two are a workaround for a bug in QT. Remove once it is fixed
        case Qt::Key_CapsLock:
        case Qt::Key_Shift:
            break;
        case Qt::Key_Up:
            term_send_special( terminal, TERM_KEY_UP );
            break;
        case Qt::Key_Down:
            term_send_special( terminal, TERM_KEY_DOWN );
            break;
        case Qt::Key_Right:
            term_send_special( terminal, TERM_KEY_RIGHT );
            break;
        case Qt::Key_Left:
            term_send_special( terminal, TERM_KEY_LEFT );
            break;
        default:
            term_send_data( terminal, event->text().toUtf8().constData(), event->text().count() );
            break;
    }
}

void QTerm::resizeEvent(QResizeEvent *event)
{
    if( char_width != 0 && char_height != 0 ) {
#ifdef __QNX__
        {
            int kbd_height;
            kbd_height = BlackBerry::Keyboard::instance().keyboardHeight();
            term_resize( terminal, event->size().width() / char_width, (event->size().height() - kbd_height) / char_height, 0 );
        }
#else
        term_resize( terminal, event->size().width() / char_width, event->size().height() / char_height, 0 );
#endif
    }
}

int main(int argc, char *argv[])
{
    term_t terminal;
    if( !term_create( &terminal ) ) {
        fprintf(stderr, "Failed to create terminal (%s)\n", strerror( errno ) );
        exit(1);
    }
    if( !term_begin( terminal, WIDTH, HEIGHT, 0 ) ) {
        fprintf(stderr, "Failed to begin terminal (%s)\n", strerror( errno ) );
        exit(1);
    }
    {
        QCoreApplication::addLibraryPath("app/native/lib");
        QApplication app(argc, argv);

        QTerm term(NULL, terminal);
        term.show();

        return app.exec();
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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 "syzygy/block_graph/block_util.h"

#include "gtest/gtest.h"
#include "syzygy/block_graph/basic_block_assembler.h"
#include "syzygy/block_graph/basic_block_test_util.h"

namespace block_graph {

namespace {

class BlockUtilTest: public testing::Test {
 public:
  BlockUtilTest()
      : bb_(NULL),
        start_addr_(0xF00D) {
    bb_ = subgraph_.AddBasicCodeBlock("foo");
  }

  BlockGraph::Size AddInstructions(bool add_source_ranges) {
    using assm::eax;
    using assm::ebp;
    using assm::esp;

    BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());

    assm.push(ebp);
    assm.mov(ebp, esp);
    assm.mov(eax, Operand(ebp,  Displacement(8)));
    assm.pop(ebp);
    // assm.ret(0);

    BasicBlock::Instructions::iterator inst_it(bb_->instructions().begin());
    BlockGraph::RelativeAddress next_addr(start_addr_);

    BasicBlock::Offset next_offs = 0;
    for (; inst_it != bb_->instructions().end(); ++inst_it) {
      if (add_source_ranges)
        inst_it->set_source_range(
            Instruction::SourceRange(next_addr, inst_it->size()));

      next_addr += inst_it->size();
      next_offs += inst_it->size();
    }

    BasicBlockReference ref(BlockGraph::PC_RELATIVE_REF, 4, bb_);
    bb_->successors().push_back(
        Successor(Successor::kConditionAbove, ref, 5));
    next_offs += 5;

    if (add_source_ranges)
      bb_->successors().back().set_source_range(
          Successor::SourceRange(next_addr, 5));

    bb_->successors().push_back(
        Successor(Successor::kConditionBelowOrEqual, ref, 0));

    return next_offs;
  }

 protected:
  BlockGraph image_;
  BlockGraph::RelativeAddress start_addr_;
  BasicBlockSubGraph subgraph_;
  BasicCodeBlock* bb_;
};

}  // namespace

TEST_F(BlockUtilTest, GetBasicBlockSourceRangeEmptyFails) {
  BlockGraph::Block::SourceRange source_range;
  ASSERT_FALSE(GetBasicBlockSourceRange(*bb_, &source_range));
  EXPECT_EQ(0, source_range.size());
}

TEST_F(BlockUtilTest, GetBasicBlockSourceRangeNonContiguousFails) {
  // Make the range non-contiguous by pushing the successor out one byte.
  BlockGraph::Block::SourceRange range =
      bb_->successors().front().source_range();
  bb_->successors().front().set_source_range(
      BlockGraph::Block::SourceRange(range.start() + 1, range.size()));

  BlockGraph::Block::SourceRange source_range;
  ASSERT_FALSE(GetBasicBlockSourceRange(*bb_, &source_range));
  EXPECT_EQ(0, source_range.size());
}

TEST_F(BlockUtilTest, GetBasicBlockSourceRangeSequentialSucceeds) {
  BlockGraph::Size instr_len = AddInstructions(true);

  BlockGraph::Block::SourceRange source_range;
  ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
  BlockGraph::Block::SourceRange expected_range(
      BlockGraph::RelativeAddress(0xF00D), instr_len);
  EXPECT_EQ(expected_range, source_range);
}

TEST_F(BlockUtilTest, GetBasicBlockSourceRangeNonSequentialSucceeds) {
  BlockGraph::Size instr_len = AddInstructions(true);

  // Shuffle the ranges by flipping the first and last ranges.
  BlockGraph::Block::SourceRange temp =
      bb_->successors().front().source_range();
  bb_->successors().front().set_source_range(
      bb_->instructions().front().source_range());
  bb_->instructions().front().set_source_range(temp);

  BlockGraph::Block::SourceRange source_range;
  ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
  BlockGraph::Block::SourceRange expected_range(
      BlockGraph::RelativeAddress(0xF00D), instr_len);
  EXPECT_EQ(expected_range, source_range);
}

TEST_F(BlockUtilTest, GetBasicBlockSourceRangePrependInstructionsSucceeds) {
  BlockGraph::Size instr_len = AddInstructions(true);

  // Prepend some instrumentation-like code.
  BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  assm.push(Immediate(0xBADF00D));
  assm.call(Immediate(bb_));

  BlockGraph::Block::SourceRange source_range;
  ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
  BlockGraph::Block::SourceRange expected_range(
      BlockGraph::RelativeAddress(0xF00D), instr_len);
  EXPECT_EQ(expected_range, source_range);
}

TEST_F(BlockUtilTest, IsUnsafeReference) {
  // Some safe blocks.
  BlockGraph::Block* s1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s1");
  BlockGraph::Block* s2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s2");

  // Some unsafe blocks.
  BlockGraph::Block* u1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "u1");
  u1->set_attribute(BlockGraph::HAS_INLINE_ASSEMBLY);
  BlockGraph::Block* u2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "u2");
  u2->set_attribute(BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);

  // If neither or only one has an unsafe attribute then it's not unsafe.
  EXPECT_FALSE(IsUnsafeReference(s1, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      s2, 0, 0)));
  EXPECT_FALSE(IsUnsafeReference(s1, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      u1, 0, 0)));
  EXPECT_FALSE(IsUnsafeReference(u2, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      s2, 0, 0)));

  // If the reference points to a non-zero offset then it's unsafe.
  EXPECT_TRUE(IsUnsafeReference(s1, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      s2, 4, 4)));

  // If both the referring and referred blocks have unsafe attributes,
  // the reference is unsafe.
  EXPECT_TRUE(IsUnsafeReference(u1, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      u2, 0, 0)));
}

TEST_F(BlockUtilTest, CheckNoUnexpectedStackFrameManipulation) {
  // Prepend some instrumentation with a conventional calling convention.
  BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  assm.push(assm::ebp);
  assm.mov(assm::ebp, assm::esp);
  assm.mov(assm::eax, Operand(assm::ebp,  Displacement(8)));
  assm.pop(assm::ebp);
  assm.ret(0);

  EXPECT_FALSE(HasUnexpectedStackFrameManipulation(&subgraph_));
}

TEST_F(BlockUtilTest, CheckInvalidInstructionUnexpectedStackFrameManipulation) {
  // Prepend some instrumentation with a conventional calling convention.
  BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  assm.push(assm::ebp);
  assm.mov(assm::ebp, assm::esp);
  // The instruction LEA is invalid stack frame manipulation.
  assm.lea(assm::ebp, Operand(assm::ebp,  Displacement(8)));
  assm.pop(assm::ebp);
  assm.ret(0);

  EXPECT_TRUE(HasUnexpectedStackFrameManipulation(&subgraph_));
}

TEST_F(BlockUtilTest, CheckInvalidRegisterUnexpectedStackFrameManipulation) {
  // Prepend some instrumentation with a conventional calling convention.
  BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  assm.push(assm::ebp);
  // The instruction MOV use an invalid register EAX.
  assm.mov(assm::ebp, assm::eax);
  assm.lea(assm::ebp, Operand(assm::ebp,  Displacement(8)));
  assm.pop(assm::ebp);
  assm.ret(0);

  EXPECT_TRUE(HasUnexpectedStackFrameManipulation(&subgraph_));
}

namespace {

// A utility class for using the test data built around the function in
// basic_block_assembly_func.asm.
class BlockUtilOnTestDataTest : public testing::BasicBlockTest {
 public:
  virtual void SetUp() override {
    BasicBlockTest::SetUp();
    ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
  }
};

}  // namespace

TEST_F(BlockUtilOnTestDataTest, GetJumpTableSize) {
  block_graph::BlockGraph::BlockMap::const_iterator block_iter =
      block_graph_.blocks().begin();

  size_t table_size = 0;
  bool table_found = false;

  // Iterates over the blocks of the block_graph. We expect to find only one
  // block containing one jump table.
  for (; block_iter != block_graph_.blocks().end(); ++block_iter) {
    if (block_iter->second.type() != BlockGraph::CODE_BLOCK)
      continue;

    // Iterates over the labels of the block to find the jump tables.
    BlockGraph::Block::LabelMap::const_iterator iter_label =
        block_iter->second.labels().begin();
    for (; iter_label != block_iter->second.labels().end(); ++iter_label) {
      if (!iter_label->second.has_attributes(BlockGraph::JUMP_TABLE_LABEL))
        continue;

      // There's only one jump table in the test data.
      EXPECT_FALSE(table_found);
      table_found = true;

      EXPECT_TRUE(block_graph::GetJumpTableSize(&block_iter->second,
                                                iter_label,
                                                &table_size));
    }
  }
  EXPECT_EQ(3U, table_size);
}

}  // namespace block_graph
<commit_msg>Fix a bug introduced in the deps roll.<commit_after>// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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 "syzygy/block_graph/block_util.h"

#include "gtest/gtest.h"
#include "syzygy/block_graph/basic_block_assembler.h"
#include "syzygy/block_graph/basic_block_test_util.h"

namespace block_graph {

namespace {

class BlockUtilTest: public testing::Test {
 public:
  BlockUtilTest()
      : bb_(NULL),
        start_addr_(0xF00D) {
    bb_ = subgraph_.AddBasicCodeBlock("foo");
  }

  BlockGraph::Size AddInstructions(bool add_source_ranges) {
    using assm::eax;
    using assm::ebp;
    using assm::esp;

    BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());

    assm.push(ebp);
    assm.mov(ebp, esp);
    assm.mov(eax, Operand(ebp,  Displacement(8)));
    assm.pop(ebp);
    // assm.ret(0);

    BasicBlock::Instructions::iterator inst_it(bb_->instructions().begin());
    BlockGraph::RelativeAddress next_addr(start_addr_);

    BasicBlock::Offset next_offs = 0;
    for (; inst_it != bb_->instructions().end(); ++inst_it) {
      if (add_source_ranges)
        inst_it->set_source_range(
            Instruction::SourceRange(next_addr, inst_it->size()));

      next_addr += inst_it->size();
      next_offs += inst_it->size();
    }

    BasicBlockReference ref(BlockGraph::PC_RELATIVE_REF, 4, bb_);
    bb_->successors().push_back(
        Successor(Successor::kConditionAbove, ref, 5));
    next_offs += 5;

    if (add_source_ranges)
      bb_->successors().back().set_source_range(
          Successor::SourceRange(next_addr, 5));

    bb_->successors().push_back(
        Successor(Successor::kConditionBelowOrEqual, ref, 0));

    return next_offs;
  }

 protected:
  BlockGraph image_;
  BlockGraph::RelativeAddress start_addr_;
  BasicBlockSubGraph subgraph_;
  BasicCodeBlock* bb_;
};

}  // namespace

TEST_F(BlockUtilTest, GetBasicBlockSourceRangeEmptyFails) {
  AddInstructions(false);
  BlockGraph::Block::SourceRange source_range;
  ASSERT_FALSE(GetBasicBlockSourceRange(*bb_, &source_range));
  EXPECT_EQ(0, source_range.size());
}

TEST_F(BlockUtilTest, GetBasicBlockSourceRangeNonContiguousFails) {
  AddInstructions(true);
  // Make the range non-contiguous by pushing the successor out one byte.
  BlockGraph::Block::SourceRange range =
      bb_->successors().front().source_range();
  bb_->successors().front().set_source_range(
      BlockGraph::Block::SourceRange(range.start() + 1, range.size()));

  BlockGraph::Block::SourceRange source_range;
  ASSERT_FALSE(GetBasicBlockSourceRange(*bb_, &source_range));
  EXPECT_EQ(0, source_range.size());
}

TEST_F(BlockUtilTest, GetBasicBlockSourceRangeSequentialSucceeds) {
  BlockGraph::Size instr_len = AddInstructions(true);

  BlockGraph::Block::SourceRange source_range;
  ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
  BlockGraph::Block::SourceRange expected_range(
      BlockGraph::RelativeAddress(0xF00D), instr_len);
  EXPECT_EQ(expected_range, source_range);
}

TEST_F(BlockUtilTest, GetBasicBlockSourceRangeNonSequentialSucceeds) {
  BlockGraph::Size instr_len = AddInstructions(true);

  // Shuffle the ranges by flipping the first and last ranges.
  BlockGraph::Block::SourceRange temp =
      bb_->successors().front().source_range();
  bb_->successors().front().set_source_range(
      bb_->instructions().front().source_range());
  bb_->instructions().front().set_source_range(temp);

  BlockGraph::Block::SourceRange source_range;
  ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
  BlockGraph::Block::SourceRange expected_range(
      BlockGraph::RelativeAddress(0xF00D), instr_len);
  EXPECT_EQ(expected_range, source_range);
}

TEST_F(BlockUtilTest, GetBasicBlockSourceRangePrependInstructionsSucceeds) {
  BlockGraph::Size instr_len = AddInstructions(true);

  // Prepend some instrumentation-like code.
  BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  assm.push(Immediate(0xBADF00D));
  assm.call(Immediate(bb_));

  BlockGraph::Block::SourceRange source_range;
  ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
  BlockGraph::Block::SourceRange expected_range(
      BlockGraph::RelativeAddress(0xF00D), instr_len);
  EXPECT_EQ(expected_range, source_range);
}

TEST_F(BlockUtilTest, IsUnsafeReference) {
  // Some safe blocks.
  BlockGraph::Block* s1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s1");
  BlockGraph::Block* s2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s2");

  // Some unsafe blocks.
  BlockGraph::Block* u1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "u1");
  u1->set_attribute(BlockGraph::HAS_INLINE_ASSEMBLY);
  BlockGraph::Block* u2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "u2");
  u2->set_attribute(BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);

  // If neither or only one has an unsafe attribute then it's not unsafe.
  EXPECT_FALSE(IsUnsafeReference(s1, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      s2, 0, 0)));
  EXPECT_FALSE(IsUnsafeReference(s1, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      u1, 0, 0)));
  EXPECT_FALSE(IsUnsafeReference(u2, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      s2, 0, 0)));

  // If the reference points to a non-zero offset then it's unsafe.
  EXPECT_TRUE(IsUnsafeReference(s1, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      s2, 4, 4)));

  // If both the referring and referred blocks have unsafe attributes,
  // the reference is unsafe.
  EXPECT_TRUE(IsUnsafeReference(u1, BlockGraph::Reference(
      BlockGraph::PC_RELATIVE_REF,
      BlockGraph::Reference::kMaximumSize,
      u2, 0, 0)));
}

TEST_F(BlockUtilTest, CheckNoUnexpectedStackFrameManipulation) {
  // Prepend some instrumentation with a conventional calling convention.
  BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  assm.push(assm::ebp);
  assm.mov(assm::ebp, assm::esp);
  assm.mov(assm::eax, Operand(assm::ebp,  Displacement(8)));
  assm.pop(assm::ebp);
  assm.ret(0);

  EXPECT_FALSE(HasUnexpectedStackFrameManipulation(&subgraph_));
}

TEST_F(BlockUtilTest, CheckInvalidInstructionUnexpectedStackFrameManipulation) {
  // Prepend some instrumentation with a conventional calling convention.
  BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  assm.push(assm::ebp);
  assm.mov(assm::ebp, assm::esp);
  // The instruction LEA is invalid stack frame manipulation.
  assm.lea(assm::ebp, Operand(assm::ebp,  Displacement(8)));
  assm.pop(assm::ebp);
  assm.ret(0);

  EXPECT_TRUE(HasUnexpectedStackFrameManipulation(&subgraph_));
}

TEST_F(BlockUtilTest, CheckInvalidRegisterUnexpectedStackFrameManipulation) {
  // Prepend some instrumentation with a conventional calling convention.
  BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  assm.push(assm::ebp);
  // The instruction MOV use an invalid register EAX.
  assm.mov(assm::ebp, assm::eax);
  assm.lea(assm::ebp, Operand(assm::ebp,  Displacement(8)));
  assm.pop(assm::ebp);
  assm.ret(0);

  EXPECT_TRUE(HasUnexpectedStackFrameManipulation(&subgraph_));
}

namespace {

// A utility class for using the test data built around the function in
// basic_block_assembly_func.asm.
class BlockUtilOnTestDataTest : public testing::BasicBlockTest {
 public:
  virtual void SetUp() override {
    BasicBlockTest::SetUp();
    ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
  }
};

}  // namespace

TEST_F(BlockUtilOnTestDataTest, GetJumpTableSize) {
  block_graph::BlockGraph::BlockMap::const_iterator block_iter =
      block_graph_.blocks().begin();

  size_t table_size = 0;
  bool table_found = false;

  // Iterates over the blocks of the block_graph. We expect to find only one
  // block containing one jump table.
  for (; block_iter != block_graph_.blocks().end(); ++block_iter) {
    if (block_iter->second.type() != BlockGraph::CODE_BLOCK)
      continue;

    // Iterates over the labels of the block to find the jump tables.
    BlockGraph::Block::LabelMap::const_iterator iter_label =
        block_iter->second.labels().begin();
    for (; iter_label != block_iter->second.labels().end(); ++iter_label) {
      if (!iter_label->second.has_attributes(BlockGraph::JUMP_TABLE_LABEL))
        continue;

      // There's only one jump table in the test data.
      EXPECT_FALSE(table_found);
      table_found = true;

      EXPECT_TRUE(block_graph::GetJumpTableSize(&block_iter->second,
                                                iter_label,
                                                &table_size));
    }
  }
  EXPECT_EQ(3U, table_size);
}

}  // namespace block_graph
<|endoftext|>