<commit_before>/*
 * DynamicMat.hpp
 *
 *  Created on: Nov 10, 2013
 *      Author: andresf
 */

#ifndef DYNAMICMAT_HPP_
#define DYNAMICMAT_HPP_

#include <map>
#include <math.h>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <vector>

#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>

#ifndef MAX_CACHE_SIZE
#define MAX_CACHE_SIZE 524288000 // ~500 MB
#endif

// Pair holding image index (first) and (inclusive) starting descriptors index (second)
typedef int Image;

static std::vector<Image> DEFAULT_INDICES;
static std::vector<std::string> DEFAULT_FILENAMES;

namespace vlr {

class Mat {

public:

	static const size_t MAX_MEM = MAX_CACHE_SIZE;

private:

	double m_capacity = 0.0;
	int m_descriptorType = -1;
	size_t m_elemSize = 0;
	std::vector<Image> m_imagesIndex, m_descriptorsIndex;
	std::vector<std::string> m_descriptorsFilenames;

	/** Attributes of the cache **/
	size_t m_memoryCount = 0;
	std::stack<int> m_cachingOrder;
	std::map<int, cv::Mat>* m_descriptorsCache;

public:

	int rows = 0;
	int cols = 0;

public:

	/**
	 * Class empty constructor.
	 */
	Mat();

	/**
	 * Copy constructor.
	 *
	 * @param other - Reference to an instance where to copy properties from
	 */
	Mat(const Mat& other);

	/**
	 * Class constructor.
	 *
	 * @param keysFilenames - Reference to a vector of descriptor filenames
	 */
	Mat(std::vector<std::string>& keysFilenames);

	/**
	 * Class destroyer.
	 */
	virtual ~Mat();

	/**
	 * Assignment operator.
	 *
	 * @param other - Reference to an instance where to copy properties from
	 * @return reference to the new instance
	 */
	Mat& operator=(const Mat& other);

	/**
	 * Retrieves the requested descriptor by obtaining it from cache
	 * and if necessary load the associated descriptor.
	 *
	 * @param descriptorIndex - Index of the descriptor to retrieve
	 * @return requested descriptor
	 */
	cv::Mat row(int descriptorIndex);

	/**
	 * Returns type of descriptors held by the virtual big descriptors matrix.
	 *
	 * @return descriptors type
	 */
	int type() const;

	size_t elemSize() const;

	/**
	 * Returns true if the matrix is empty.
	 *
	 * @return true if rows counter is zero, false otherwise
	 */
	bool empty() const;

	/**
	 * Swaps the cache content by an empty vector of the same size.
	 */
	void clearCache();

	/**
	 * Returns the maximum number of descriptors that can be stored
	 * given the maximum size of the cache
	 *
	 * @return cache capacity in number of descriptors
	 */
	double getCapacity() const {
		return m_capacity;
	}

	/** Getters **/

	/**
	 * Returns a reference to the index descriptors holding the
	 * index of image it belongs to and the starting index of the
	 * virtual big descriptors matrix.
	 *
	 * @return index of descriptors
	 */
	const std::vector<Image>& getDescriptorsIndex() const {
		return m_imagesIndex;
	}

	/**
	 * Returns a reference to the vector of descriptors filenames.
	 *
	 * @return descriptors filenames
	 */
	const std::vector<std::string>& getDescriptorsFilenames() const {
		return m_descriptorsFilenames;
	}

	/**
	 * Returns the count of memory used by the matrices loaded in cache.
	 *
	 * @return memory count in Bytes
	 */
	size_t getMemoryCount() const {
		return m_memoryCount;
	}

private:

	/**
	 * Computes used memory by the given descriptors matrix
	 *
	 * @param descriptors - a reference to a matrix containing descriptors
	 * @return number of bytes used
	 */
	size_t rowMemorySize() {
		return cols * m_elemSize;
	}

};

static vlr::Mat DEFAULT_INPUTDATA = vlr::Mat();

} /* namespace vlr */

#endif /* DYNAMICMAT_HPP_ */
<commit_msg>Common/include/DynamicMat.hpp * Defined max cach size without condition. * Removed type definition.<commit_after>/*
 * DynamicMat.hpp
 *
 *  Created on: Nov 10, 2013
 *      Author: andresf
 */

#ifndef DYNAMICMAT_HPP_
#define DYNAMICMAT_HPP_

#include <map>
#include <math.h>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <vector>

#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>

#define MAX_CACHE_SIZE 524288000 // ~500 MB

static std::vector<int> DEFAULT_INDICES;
static std::vector<std::string> DEFAULT_FILENAMES;

namespace vlr {

class Mat {

public:

	static const size_t MAX_MEM = MAX_CACHE_SIZE;

private:

	double m_capacity = 0.0;
	int m_descriptorType = -1;
	size_t m_elemSize = 0;
	std::vector<int> m_imagesIndex, m_descriptorsIndex;
	std::vector<std::string> m_descriptorsFilenames;

	/** Attributes of the cache **/
	size_t m_memoryCount = 0;
	std::stack<int> m_cachingOrder;
	std::map<int, cv::Mat>* m_descriptorsCache;

public:

	int rows = 0;
	int cols = 0;

public:

	/**
	 * Class empty constructor.
	 */
	Mat();

	/**
	 * Copy constructor.
	 *
	 * @param other - Reference to an instance where to copy properties from
	 */
	Mat(const Mat& other);

	/**
	 * Class constructor.
	 *
	 * @param keysFilenames - Reference to a vector of descriptor filenames
	 */
	Mat(std::vector<std::string>& keysFilenames);

	/**
	 * Class destroyer.
	 */
	virtual ~Mat();

	/**
	 * Assignment operator.
	 *
	 * @param other - Reference to an instance where to copy properties from
	 * @return reference to the new instance
	 */
	Mat& operator=(const Mat& other);

	/**
	 * Retrieves the requested descriptor by obtaining it from cache
	 * and if necessary load the associated descriptor.
	 *
	 * @param descriptorIndex - Index of the descriptor to retrieve
	 * @return requested descriptor
	 */
	cv::Mat row(int descriptorIndex);

	/**
	 * Returns type of descriptors held by the virtual big descriptors matrix.
	 *
	 * @return descriptors type
	 */
	int type() const;

	size_t elemSize() const;

	/**
	 * Returns true if the matrix is empty.
	 *
	 * @return true if rows counter is zero, false otherwise
	 */
	bool empty() const;

	/**
	 * Swaps the cache content by an empty vector of the same size.
	 */
	void clearCache();

	/**
	 * Returns the maximum number of descriptors that can be stored
	 * given the maximum size of the cache
	 *
	 * @return cache capacity in number of descriptors
	 */
	double getCapacity() const {
		return m_capacity;
	}

	/** Getters **/

	/**
	 * Returns a reference to the index descriptors holding the
	 * index of image it belongs to and the starting index of the
	 * virtual big descriptors matrix.
	 *
	 * @return index of descriptors
	 */
	const std::vector<int>& getDescriptorsIndex() const {
		return m_imagesIndex;
	}

	/**
	 * Returns a reference to the vector of descriptors filenames.
	 *
	 * @return descriptors filenames
	 */
	const std::vector<std::string>& getDescriptorsFilenames() const {
		return m_descriptorsFilenames;
	}

	/**
	 * Returns the count of memory used by the matrices loaded in cache.
	 *
	 * @return memory count in Bytes
	 */
	size_t getMemoryCount() const {
		return m_memoryCount;
	}

private:

	/**
	 * Computes used memory by the given descriptors matrix
	 *
	 * @param descriptors - a reference to a matrix containing descriptors
	 * @return number of bytes used
	 */
	size_t rowMemorySize() {
		return cols * m_elemSize;
	}

};

static vlr::Mat DEFAULT_INPUTDATA = vlr::Mat();

} /* namespace vlr */

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


<commit_before>// @(#)root/hist:$Id$
// Author: Lorenzo Moneta 12/06/07

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
 *                                                                    *
 *                                                                    *
 **********************************************************************/

// helper functions and classes used internally by TF1

#include "TF1Helper.h"
#include "TVirtualFitter.h"
#include "TError.h"
#include <vector>
#include <cmath>
#include <cassert>

#include <iostream>

namespace ROOT {

   namespace TF1Helper{

double IntegralError(TF1 * func, double a, double b, double epsilon) {

   // calculate the eror on an integral from a to b of a parametetric function f when the parameters
   // are estimated from a fit and have an error represented by the covariance matrix of the fit.
   // The latest fit result is used

   // need to create the gradient functions w.r.t to the parameters

   // loop on all parameters
   int npar = func->GetNpar();
   int nfreepar = func->GetNumberFreeParameters();

   double * epar = func->GetParErrors();

   // get covariance matrix from latest fit
   TVirtualFitter * fitter = TVirtualFitter::GetFitter();
   if (fitter == 0) {
      Error("TF1Helper","No existing fitter");
      return 0;
   }
   double * covMatrix = fitter->GetCovarianceMatrix();
   if (covMatrix == 0) {
      Error("TF1Helper","Fitter has no covariance matrix");
      return 0;
   }
   // check that fitter and function are in sync
   if (fitter->GetNumberFreeParameters() != nfreepar) {
      Error("TF1Helper","Wrong Fitter for TF1");
      return 0;
   }

   std::vector<double> ig;
   ig.reserve(nfreepar);
   for (int i=0; i < npar; ++i) {

      // check also the parameter values
      if (fitter->GetParameter(i) != func->GetParameter(i) ) {
         Error("TF1Helper","Wrong Fitter for TF1");
         return 0;
      }

      // check that parameter is not fixed
      if (! fitter->IsFixed(i) ) {
         // should check the limits
         double integral  = 0;
         if (epar[i] > 0 ) {
            TF1 gradFunc("gradFunc",TGradientParFunction(i,func),0,0,0);
            integral = gradFunc.Integral(a,b,(double*)0,epsilon);
         }
         ig.push_back(integral);
      }
   }
   // number of free parameters and size of corr matrix
   assert( int(ig.size()) == nfreepar);

   double err2 = 0;
   for (int i = 0; i < nfreepar; ++i) {
      double s = 0;
      for (int j =0; j < nfreepar; ++j) {
         std::cout << i << "  " << j << " ig " << ig[i] << "  " << ig[j] << "  " << covMatrix[i*npar + j] << "  " << s << std::endl;
         s += ig[j] * covMatrix[i*npar + j] ;
      }

      err2 += ig[i] * s;
   }

   return std::sqrt(err2);

}

} // end namespace TF1Helper

} // end namespace ROOT
<commit_msg>remove a left-out debug statement<commit_after>// @(#)root/hist:$Id$
// Author: Lorenzo Moneta 12/06/07

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
 *                                                                    *
 *                                                                    *
 **********************************************************************/

// helper functions and classes used internally by TF1

#include "TF1Helper.h"
#include "TVirtualFitter.h"
#include "TError.h"
#include <vector>
#include <cmath>
#include <cassert>

namespace ROOT {

   namespace TF1Helper{

double IntegralError(TF1 * func, double a, double b, double epsilon) {

   // calculate the eror on an integral from a to b of a parametetric function f when the parameters
   // are estimated from a fit and have an error represented by the covariance matrix of the fit.
   // The latest fit result is used

   // need to create the gradient functions w.r.t to the parameters

   // loop on all parameters
   int npar = func->GetNpar();
   int nfreepar = func->GetNumberFreeParameters();

   double * epar = func->GetParErrors();

   // get covariance matrix from latest fit
   TVirtualFitter * fitter = TVirtualFitter::GetFitter();
   if (fitter == 0) {
      Error("TF1Helper","No existing fitter");
      return 0;
   }
   double * covMatrix = fitter->GetCovarianceMatrix();
   if (covMatrix == 0) {
      Error("TF1Helper","Fitter has no covariance matrix");
      return 0;
   }
   // check that fitter and function are in sync
   if (fitter->GetNumberFreeParameters() != nfreepar) {
      Error("TF1Helper","Wrong Fitter for TF1");
      return 0;
   }

   std::vector<double> ig;
   ig.reserve(nfreepar);
   for (int i=0; i < npar; ++i) {

      // check also the parameter values
      if (fitter->GetParameter(i) != func->GetParameter(i) ) {
         Error("TF1Helper","Wrong Fitter for TF1");
         return 0;
      }

      // check that parameter is not fixed
      if (! fitter->IsFixed(i) ) {
         // should check the limits
         double integral  = 0;
         if (epar[i] > 0 ) {
            TF1 gradFunc("gradFunc",TGradientParFunction(i,func),0,0,0);
            integral = gradFunc.Integral(a,b,(double*)0,epsilon);
         }
         ig.push_back(integral);
      }
   }
   // number of free parameters and size of corr matrix
   assert( int(ig.size()) == nfreepar);

   double err2 = 0;
   for (int i = 0; i < nfreepar; ++i) {
      double s = 0;
      for (int j =0; j < nfreepar; ++j)
         s += ig[j] * covMatrix[i*npar + j] ;

      err2 += ig[i] * s;
   }

   return std::sqrt(err2);

}

} // end namespace TF1Helper

} // end namespace ROOT
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2020 - 2021 Pedro Falcato
 * This file is part of Onyx, and is released under the terms of the MIT License
 * check LICENSE at the root directory for more information
 *
 * SPDX-License-Identifier: MIT
 */

#include "uart8250.h"

#include <stdint.h>

#include <onyx/dev.h>
#include <onyx/dpc.h>
#include <onyx/driver.h>
#include <onyx/irq.h>
#include <onyx/panic.h>
#include <onyx/port_io.h>
#include <onyx/serial.h>
#include <onyx/tty.h>

static driver serial_platform_driver = {.name = "uart8250-platform",
                                        .bus_type_node = {&serial_platform_driver}};

device uart8250_platform_device{"uart8250", nullptr, nullptr};

irqstatus_t uart8250_port::on_irq()
{
    auto st = read<uint8_t>(uart8250_register::interrupt_identification);

    if (st & UART8250_IIR_IRQ_PENDING)
        return IRQ_UNHANDLED;

    auto reason = UART8250_IIR_REASON(st);
    if (reason & UART8250_IIR_RX_DATA_AVL)
    {
        auto data = read<uint8_t>(uart8250_register::data);
        receive_byte(data);
        return IRQ_HANDLED;
    }

    return IRQ_UNHANDLED;
}

void uart8250_port::set_baud_rate(uint16_t rate)
{
    auto div_value = calculate_divisor(rate);

    assert(div_value != 0);

    uint8_t old_val = read<uint8_t>(uart8250_register::line_control);
    write<uint8_t>(uart8250_register::line_control, old_val | UART8250_LCR_DLAB);
    write<uint8_t>(uart8250_register::lsb_divisor, div_value & 0xff);
    write<uint8_t>(uart8250_register::msb_divisor, div_value >> 8);

    write<uint8_t>(uart8250_register::line_control, old_val);
}

bool uart8250_port::test()
{
    write<uint8_t>(uart8250_register::modem_control, UART8250_MCR_LOOPBACK);
    write<uint8_t>(uart8250_register::data, 0xcd);

    return read<uint8_t>(uart8250_register::data) == 0xcd;
}

bool uart8250_port::tx_empty()
{
    return read<uint8_t>(uart8250_register::line_status) & UART8250_LSR_TX_BUF_EMPTY;
}

bool uart8250_port::rx_rdy()
{
    return read<uint8_t>(uart8250_register::line_status) & UART8250_LSR_DATA_RDY;
}

void uart8250_port::write_byte(uint8_t c)
{
    while (!tx_empty())
        ;

    write<uint8_t>(uart8250_register::data, c);
}

void uart8250_port::write(const char *s, size_t size, bool is_debug_console)
{
    scoped_lock g{lock_};
    for (size_t i = 0; i < size; i++)
    {
        auto byte = static_cast<uint8_t>(s[i]);

        // Needed for basic printing as a debug console
        if (is_debug_console && byte == '\n') [[unlikely]]
            write_byte('\r');
        write_byte(static_cast<uint8_t>(*(s + i)));
    }
}

alignas(uart8250_port) static char com1_buf[sizeof(uart8250_port)];
uart8250_port *com1;

bool uart8250_port::present()
{
    static constexpr uint8_t test_val = 0xcd;
    write<uint8_t>(uart8250_register::scratch_register, test_val);

    auto present = read<uint8_t>(uart8250_register::scratch_register);

    return present == test_val;
}

irqstatus_t uart8250_irq(irq_context *ctx, void *cookie)
{
    auto port = reinterpret_cast<uart8250_port *>(cookie);

    return port->on_irq();
}

/**
 * @brief Initialises the serial port as a debug console
 *
 * @return True if success, else false.
 */
bool uart8250_port::early_init()
{
    /* Disable interrupts */
    write<uint8_t>(uart8250_register::interrupt_enable, 0);

    /* Then we set the baud rate of the port */
    set_baud_rate(default_baud_rate);

    /* Set the word length to 8-bits per word */
    write<uint8_t>(uart8250_register::line_control, UART8250_LCR_WORD_LENGTH(UART8250_LCR_8BIT_WL));

    /* Set some FIFO settings */
    uint8_t fcr = UART8250_FCR_CLR_TX_FIFO | UART8250_FCR_CLR_RCV_FIFO | UART8250_FCR_FIFO_ENABLE |
                  UART8250_FCR_INT_TRIGGER_14BYTE;

    write<uint8_t>(uart8250_register::fifo_control, fcr);

    /* Signal that we're ready to send and ready to receive */
    // Note: UART8250_MCR_GPO2_ENABLE = Enable interrupts as well. It's weird, but we also need to
    // set this.
    write<uint8_t>(uart8250_register::modem_control, UART8250_MCR_GPO2_ENABLE |
                                                         UART8250_MCR_DATA_TERMINAL_RDY |
                                                         UART8250_MCR_REQ_TO_SEND);

    return true;
}

/**
 * @brief Write bytes to the serial port
 *
 * @param buffer Buffer
 * @param size Length
 * @return Positive byte count or negative error code
 */
ssize_t uart8250_port::write_serial(const void *buffer, size_t size)
{
    write((const char *) buffer, size);
    return size;
}

/**
 * @brief Initialises the serial port as a standard serial port
 *
 * @return True if success, else false
 */
bool uart8250_port::init()
{
    if (!early_init())
        return false;

    install_irq(irq_, uart8250_irq, dev_, IRQ_FLAG_REGULAR, this);

    /* Re-enable interrupts */
    write<uint8_t>(uart8250_register::interrupt_enable, UART8250_IER_DATA_AVAIL);

    return init_tty();
}

void platform_serial_init(void)
{
    com1 = new (com1_buf) uart8250_port{0x3f8, 4, &uart8250_platform_device};
    com1->early_init();
    uart8250_platform_device.driver_ = &serial_platform_driver;
}

void platform_serial_write(const char *s, size_t size)
{
    com1->write(s, size, true);
}
<commit_msg>uart8250: Add tx_empty() timeout<commit_after>/*
 * Copyright (c) 2020 - 2021 Pedro Falcato
 * This file is part of Onyx, and is released under the terms of the MIT License
 * check LICENSE at the root directory for more information
 *
 * SPDX-License-Identifier: MIT
 */

#include "uart8250.h"

#include <stdint.h>

#include <onyx/dev.h>
#include <onyx/dpc.h>
#include <onyx/driver.h>
#include <onyx/irq.h>
#include <onyx/panic.h>
#include <onyx/port_io.h>
#include <onyx/serial.h>
#include <onyx/tty.h>

static driver serial_platform_driver = {.name = "uart8250-platform",
                                        .bus_type_node = {&serial_platform_driver}};

device uart8250_platform_device{"uart8250", nullptr, nullptr};

irqstatus_t uart8250_port::on_irq()
{
    auto st = read<uint8_t>(uart8250_register::interrupt_identification);

    if (st & UART8250_IIR_IRQ_PENDING)
        return IRQ_UNHANDLED;

    auto reason = UART8250_IIR_REASON(st);
    if (reason & UART8250_IIR_RX_DATA_AVL)
    {
        auto data = read<uint8_t>(uart8250_register::data);
        receive_byte(data);
        return IRQ_HANDLED;
    }

    return IRQ_UNHANDLED;
}

void uart8250_port::set_baud_rate(uint16_t rate)
{
    auto div_value = calculate_divisor(rate);

    assert(div_value != 0);

    uint8_t old_val = read<uint8_t>(uart8250_register::line_control);
    write<uint8_t>(uart8250_register::line_control, old_val | UART8250_LCR_DLAB);
    write<uint8_t>(uart8250_register::lsb_divisor, div_value & 0xff);
    write<uint8_t>(uart8250_register::msb_divisor, div_value >> 8);

    write<uint8_t>(uart8250_register::line_control, old_val);
}

bool uart8250_port::test()
{
    write<uint8_t>(uart8250_register::modem_control, UART8250_MCR_LOOPBACK);
    write<uint8_t>(uart8250_register::data, 0xcd);

    return read<uint8_t>(uart8250_register::data) == 0xcd;
}

bool uart8250_port::tx_empty()
{
    return read<uint8_t>(uart8250_register::line_status) & UART8250_LSR_TX_BUF_EMPTY;
}

bool uart8250_port::rx_rdy()
{
    return read<uint8_t>(uart8250_register::line_status) & UART8250_LSR_DATA_RDY;
}

void uart8250_port::write_byte(uint8_t c)
{
    int st = do_with_timeout(
        [&]() -> expected<int, int> {
            if (tx_empty())
                return 0;
            return 1;
        },
        NS_PER_MS);

    if (st < 0)
        return;

    write<uint8_t>(uart8250_register::data, c);
}

void uart8250_port::write(const char *s, size_t size, bool is_debug_console)
{
    scoped_lock g{lock_};
    for (size_t i = 0; i < size; i++)
    {
        auto byte = static_cast<uint8_t>(s[i]);

        // Needed for basic printing as a debug console
        if (is_debug_console && byte == '\n') [[unlikely]]
            write_byte('\r');
        write_byte(static_cast<uint8_t>(*(s + i)));
    }
}

alignas(uart8250_port) static char com1_buf[sizeof(uart8250_port)];
uart8250_port *com1;

bool uart8250_port::present()
{
    static constexpr uint8_t test_val = 0xcd;
    write<uint8_t>(uart8250_register::scratch_register, test_val);

    auto present = read<uint8_t>(uart8250_register::scratch_register);

    return present == test_val;
}

irqstatus_t uart8250_irq(irq_context *ctx, void *cookie)
{
    auto port = reinterpret_cast<uart8250_port *>(cookie);

    return port->on_irq();
}

/**
 * @brief Initialises the serial port as a debug console
 *
 * @return True if success, else false.
 */
bool uart8250_port::early_init()
{
    /* Disable interrupts */
    write<uint8_t>(uart8250_register::interrupt_enable, 0);

    /* Then we set the baud rate of the port */
    set_baud_rate(default_baud_rate);

    /* Set the word length to 8-bits per word */
    write<uint8_t>(uart8250_register::line_control, UART8250_LCR_WORD_LENGTH(UART8250_LCR_8BIT_WL));

    /* Set some FIFO settings */
    uint8_t fcr = UART8250_FCR_CLR_TX_FIFO | UART8250_FCR_CLR_RCV_FIFO | UART8250_FCR_FIFO_ENABLE |
                  UART8250_FCR_INT_TRIGGER_14BYTE;

    write<uint8_t>(uart8250_register::fifo_control, fcr);

    /* Signal that we're ready to send and ready to receive */
    // Note: UART8250_MCR_GPO2_ENABLE = Enable interrupts as well. It's weird, but we also need to
    // set this.
    write<uint8_t>(uart8250_register::modem_control, UART8250_MCR_GPO2_ENABLE |
                                                         UART8250_MCR_DATA_TERMINAL_RDY |
                                                         UART8250_MCR_REQ_TO_SEND);

    return true;
}

/**
 * @brief Write bytes to the serial port
 *
 * @param buffer Buffer
 * @param size Length
 * @return Positive byte count or negative error code
 */
ssize_t uart8250_port::write_serial(const void *buffer, size_t size)
{
    write((const char *) buffer, size);
    return size;
}

/**
 * @brief Initialises the serial port as a standard serial port
 *
 * @return True if success, else false
 */
bool uart8250_port::init()
{
    if (!early_init())
        return false;

    install_irq(irq_, uart8250_irq, dev_, IRQ_FLAG_REGULAR, this);

    /* Re-enable interrupts */
    write<uint8_t>(uart8250_register::interrupt_enable, UART8250_IER_DATA_AVAIL);

    return init_tty();
}

void platform_serial_init(void)
{
    com1 = new (com1_buf) uart8250_port{0x3f8, 4, &uart8250_platform_device};
    com1->early_init();
    uart8250_platform_device.driver_ = &serial_platform_driver;
}

void platform_serial_write(const char *s, size_t size)
{
    com1->write(s, size, true);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "AutoPipeIstream.hxx"
#include "PipeLease.hxx"
#include "New.hxx"
#include "UnusedPtr.hxx"
#include "ForwardIstream.hxx"
#include "system/Error.hxx"
#include "io/Splice.hxx"
#include "io/SpliceSupport.hxx"

#include <assert.h>
#include <errno.h>
#include <string.h>

class AutoPipeIstream final : public ForwardIstream {
	PipeLease pipe;
	std::size_t piped = 0;

	FdTypeMask direct_mask = 0;

public:
	AutoPipeIstream(struct pool &p, UnusedIstreamPtr _input,
			PipeStock *_pipe_stock) noexcept
		:ForwardIstream(p, std::move(_input)),
		 pipe(_pipe_stock) {}

	/* virtual methods from class Istream */

	void _SetDirect(FdTypeMask mask) noexcept override;
	off_t _GetAvailable(bool partial) noexcept override;
	void _Read() noexcept override;

	void _FillBucketList(IstreamBucketList &list) override {
		if (piped > 0)
			return Istream::_FillBucketList(list);

		try {
			input.FillBucketList(list);
		} catch (...) {
			Destroy();
			throw;
		}
	}

	void _ConsumeDirect(std::size_t nbytes) noexcept override;

	int _AsFd() noexcept override;
	void _Close() noexcept override;

	/* handler */
	std::size_t OnData(const void *data, std::size_t length) noexcept override;
	IstreamDirectResult OnDirect(FdType type, int fd,
				     std::size_t max_length) noexcept override;
	void OnEof() noexcept override;
	void OnError(std::exception_ptr ep) noexcept override;

private:
	void CloseInternal() noexcept;
	void Abort(std::exception_ptr ep) noexcept;
	IstreamDirectResult Consume() noexcept;
};

void
AutoPipeIstream::CloseInternal() noexcept
{
	/* reuse the pipe only if it's empty */
	pipe.Release(piped == 0);
}

void
AutoPipeIstream::Abort(std::exception_ptr ep) noexcept
{
	CloseInternal();

	DestroyError(ep);
}

IstreamDirectResult
AutoPipeIstream::Consume() noexcept
{
	assert(pipe.IsDefined());
	assert(piped > 0);

	auto result = InvokeDirect(FdType::FD_PIPE, pipe.GetReadFd().Get(),
				   piped);
	switch (result) {
	case IstreamDirectResult::BLOCKING:
	case IstreamDirectResult::CLOSED:
		/* handler blocks or pipe was closed */
		break;

	case IstreamDirectResult::END:
		/* must not happen */
		assert(false);
		gcc_unreachable();

	case IstreamDirectResult::ERRNO:
		if (errno != EAGAIN) {
			Abort(std::make_exception_ptr(MakeErrno("read from pipe failed")));
			result = IstreamDirectResult::CLOSED;
		}

		break;

	case IstreamDirectResult::OK:
		if (piped == 0 && !input.IsDefined()) {
			/* our input has already reported EOF, and we have been
			   waiting for the pipe buffer to become empty */
			CloseInternal();
			DestroyEof();
			result = IstreamDirectResult::CLOSED;
		}

		break;
	}

	return result;
}

/*
 * istream handler
 *
 */

inline std::size_t
AutoPipeIstream::OnData(const void *data, std::size_t length) noexcept
{
	assert(HasHandler());

	if (piped > 0) {
		const auto result = Consume();
		if (result != IstreamDirectResult::OK)
			return 0;

		if (piped > 0 || !HasHandler())
			return 0;
	}

	assert(piped == 0);

	return InvokeData(data, length);
}

inline IstreamDirectResult
AutoPipeIstream::OnDirect(FdType type, int fd, std::size_t max_length) noexcept
{
	assert(HasHandler());

	if (piped > 0) {
		const auto result = Consume();
		if (result != IstreamDirectResult::OK)
			return result;

		if (piped > 0)
			/* if the pipe still isn't empty, we can't start reading
			   new input */
			return IstreamDirectResult::BLOCKING;
	}

	if (direct_mask & FdTypeMask(type))
		/* already supported by handler (maybe already a pipe) - no
		   need for wrapping it into a pipe */
		return InvokeDirect(type, fd, max_length);

	assert((type & ISTREAM_TO_PIPE) == type);

	if (!pipe.IsDefined()) {
		try {
			pipe.Create();
		} catch (...) {
			Abort(std::current_exception());
			return IstreamDirectResult::CLOSED;
		}
	}

	ssize_t nbytes = Splice(fd, pipe.GetWriteFd().Get(), max_length);
	/* don't check EAGAIN here (and don't return -2).  We assume that
	   splicing to the pipe cannot possibly block, since we flushed
	   the pipe; assume that it can only be the source file which is
	   blocking */
	if (nbytes <= 0)
		return nbytes < 0
			? IstreamDirectResult::ERRNO
			: IstreamDirectResult::END;

	input.ConsumeDirect(nbytes);

	assert(piped == 0);
	piped = (std::size_t)nbytes;

	if (Consume() == IstreamDirectResult::CLOSED)
		return IstreamDirectResult::CLOSED;

	return IstreamDirectResult::OK;
}

inline void
AutoPipeIstream::OnEof() noexcept
{
	input.Clear();

	pipe.CloseWriteIfNotStock();

	if (piped == 0) {
		CloseInternal();
		DestroyEof();
	}
}

inline void
AutoPipeIstream::OnError(std::exception_ptr ep) noexcept
{
	CloseInternal();
	input.Clear();
	DestroyError(ep);
}

/*
 * istream implementation
 *
 */

void
AutoPipeIstream::_SetDirect(FdTypeMask mask) noexcept
{
	direct_mask = mask;

	if (mask & FdType::FD_PIPE)
		/* if the handler supports the pipe, we offer our
		   services */
		mask |= ISTREAM_TO_PIPE;

	input.SetDirect(mask);
}

off_t
AutoPipeIstream::_GetAvailable(bool partial) noexcept
{
	if (gcc_likely(input.IsDefined())) {
		off_t available = input.GetAvailable(partial);
		if (piped > 0) {
			if (available != -1)
				available += piped;
			else if (partial)
				available = piped;
		}

		return available;
	} else {
		assert(piped > 0);

		return piped;
	}
}

void
AutoPipeIstream::_Read() noexcept
{
	if (piped > 0 && (Consume() != IstreamDirectResult::OK || piped > 0))
		return;

	/* at this point, the pipe must be flushed - if the pipe is
	   flushed, this stream is either closed or there must be an input
	   stream */
	assert(input.IsDefined());

	input.Read();
}

void
AutoPipeIstream::_ConsumeDirect(std::size_t nbytes) noexcept
{
	if (piped > 0) {
		assert(nbytes <= piped);
		piped -= nbytes;
		Consumed(nbytes);

		if (piped == 0)
			/* if the pipe was drained, return it to the
			   stock, to make it available to other
			   streams */
			pipe.ReleaseIfStock();
	} else {
		ForwardIstream::_ConsumeDirect(nbytes);
	}
}

int
AutoPipeIstream::_AsFd() noexcept
{
	if (piped > 0)
		/* need to flush the pipe buffer first */
		return -1;

	int fd = input.AsFd();
	if (fd >= 0) {
		CloseInternal();
		Destroy();
	}

	return fd;
}

void
AutoPipeIstream::_Close() noexcept
{
	CloseInternal();

	Destroy();
}

/*
 * constructor
 *
 */

UnusedIstreamPtr
NewAutoPipeIstream(struct pool *pool, UnusedIstreamPtr input,
		   PipeStock *pipe_stock) noexcept
{
	return NewIstreamPtr<AutoPipeIstream>(*pool, std::move(input), pipe_stock);
}
<commit_msg>Revert "istream/AutoPipe: add missing Consumed() call"<commit_after>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "AutoPipeIstream.hxx"
#include "PipeLease.hxx"
#include "New.hxx"
#include "UnusedPtr.hxx"
#include "ForwardIstream.hxx"
#include "system/Error.hxx"
#include "io/Splice.hxx"
#include "io/SpliceSupport.hxx"

#include <assert.h>
#include <errno.h>
#include <string.h>

class AutoPipeIstream final : public ForwardIstream {
	PipeLease pipe;
	std::size_t piped = 0;

	FdTypeMask direct_mask = 0;

public:
	AutoPipeIstream(struct pool &p, UnusedIstreamPtr _input,
			PipeStock *_pipe_stock) noexcept
		:ForwardIstream(p, std::move(_input)),
		 pipe(_pipe_stock) {}

	/* virtual methods from class Istream */

	void _SetDirect(FdTypeMask mask) noexcept override;
	off_t _GetAvailable(bool partial) noexcept override;
	void _Read() noexcept override;

	void _FillBucketList(IstreamBucketList &list) override {
		if (piped > 0)
			return Istream::_FillBucketList(list);

		try {
			input.FillBucketList(list);
		} catch (...) {
			Destroy();
			throw;
		}
	}

	void _ConsumeDirect(std::size_t nbytes) noexcept override;

	int _AsFd() noexcept override;
	void _Close() noexcept override;

	/* handler */
	std::size_t OnData(const void *data, std::size_t length) noexcept override;
	IstreamDirectResult OnDirect(FdType type, int fd,
				     std::size_t max_length) noexcept override;
	void OnEof() noexcept override;
	void OnError(std::exception_ptr ep) noexcept override;

private:
	void CloseInternal() noexcept;
	void Abort(std::exception_ptr ep) noexcept;
	IstreamDirectResult Consume() noexcept;
};

void
AutoPipeIstream::CloseInternal() noexcept
{
	/* reuse the pipe only if it's empty */
	pipe.Release(piped == 0);
}

void
AutoPipeIstream::Abort(std::exception_ptr ep) noexcept
{
	CloseInternal();

	DestroyError(ep);
}

IstreamDirectResult
AutoPipeIstream::Consume() noexcept
{
	assert(pipe.IsDefined());
	assert(piped > 0);

	auto result = InvokeDirect(FdType::FD_PIPE, pipe.GetReadFd().Get(),
				   piped);
	switch (result) {
	case IstreamDirectResult::BLOCKING:
	case IstreamDirectResult::CLOSED:
		/* handler blocks or pipe was closed */
		break;

	case IstreamDirectResult::END:
		/* must not happen */
		assert(false);
		gcc_unreachable();

	case IstreamDirectResult::ERRNO:
		if (errno != EAGAIN) {
			Abort(std::make_exception_ptr(MakeErrno("read from pipe failed")));
			result = IstreamDirectResult::CLOSED;
		}

		break;

	case IstreamDirectResult::OK:
		if (piped == 0 && !input.IsDefined()) {
			/* our input has already reported EOF, and we have been
			   waiting for the pipe buffer to become empty */
			CloseInternal();
			DestroyEof();
			result = IstreamDirectResult::CLOSED;
		}

		break;
	}

	return result;
}

/*
 * istream handler
 *
 */

inline std::size_t
AutoPipeIstream::OnData(const void *data, std::size_t length) noexcept
{
	assert(HasHandler());

	if (piped > 0) {
		const auto result = Consume();
		if (result != IstreamDirectResult::OK)
			return 0;

		if (piped > 0 || !HasHandler())
			return 0;
	}

	assert(piped == 0);

	return InvokeData(data, length);
}

inline IstreamDirectResult
AutoPipeIstream::OnDirect(FdType type, int fd, std::size_t max_length) noexcept
{
	assert(HasHandler());

	if (piped > 0) {
		const auto result = Consume();
		if (result != IstreamDirectResult::OK)
			return result;

		if (piped > 0)
			/* if the pipe still isn't empty, we can't start reading
			   new input */
			return IstreamDirectResult::BLOCKING;
	}

	if (direct_mask & FdTypeMask(type))
		/* already supported by handler (maybe already a pipe) - no
		   need for wrapping it into a pipe */
		return InvokeDirect(type, fd, max_length);

	assert((type & ISTREAM_TO_PIPE) == type);

	if (!pipe.IsDefined()) {
		try {
			pipe.Create();
		} catch (...) {
			Abort(std::current_exception());
			return IstreamDirectResult::CLOSED;
		}
	}

	ssize_t nbytes = Splice(fd, pipe.GetWriteFd().Get(), max_length);
	/* don't check EAGAIN here (and don't return -2).  We assume that
	   splicing to the pipe cannot possibly block, since we flushed
	   the pipe; assume that it can only be the source file which is
	   blocking */
	if (nbytes <= 0)
		return nbytes < 0
			? IstreamDirectResult::ERRNO
			: IstreamDirectResult::END;

	input.ConsumeDirect(nbytes);

	assert(piped == 0);
	piped = (std::size_t)nbytes;

	if (Consume() == IstreamDirectResult::CLOSED)
		return IstreamDirectResult::CLOSED;

	return IstreamDirectResult::OK;
}

inline void
AutoPipeIstream::OnEof() noexcept
{
	input.Clear();

	pipe.CloseWriteIfNotStock();

	if (piped == 0) {
		CloseInternal();
		DestroyEof();
	}
}

inline void
AutoPipeIstream::OnError(std::exception_ptr ep) noexcept
{
	CloseInternal();
	input.Clear();
	DestroyError(ep);
}

/*
 * istream implementation
 *
 */

void
AutoPipeIstream::_SetDirect(FdTypeMask mask) noexcept
{
	direct_mask = mask;

	if (mask & FdType::FD_PIPE)
		/* if the handler supports the pipe, we offer our
		   services */
		mask |= ISTREAM_TO_PIPE;

	input.SetDirect(mask);
}

off_t
AutoPipeIstream::_GetAvailable(bool partial) noexcept
{
	if (gcc_likely(input.IsDefined())) {
		off_t available = input.GetAvailable(partial);
		if (piped > 0) {
			if (available != -1)
				available += piped;
			else if (partial)
				available = piped;
		}

		return available;
	} else {
		assert(piped > 0);

		return piped;
	}
}

void
AutoPipeIstream::_Read() noexcept
{
	if (piped > 0 && (Consume() != IstreamDirectResult::OK || piped > 0))
		return;

	/* at this point, the pipe must be flushed - if the pipe is
	   flushed, this stream is either closed or there must be an input
	   stream */
	assert(input.IsDefined());

	input.Read();
}

void
AutoPipeIstream::_ConsumeDirect(std::size_t nbytes) noexcept
{
	if (piped > 0) {
		assert(nbytes <= piped);
		piped -= nbytes;

		if (piped == 0)
			/* if the pipe was drained, return it to the
			   stock, to make it available to other
			   streams */
			pipe.ReleaseIfStock();
	} else {
		ForwardIstream::_ConsumeDirect(nbytes);
	}
}

int
AutoPipeIstream::_AsFd() noexcept
{
	if (piped > 0)
		/* need to flush the pipe buffer first */
		return -1;

	int fd = input.AsFd();
	if (fd >= 0) {
		CloseInternal();
		Destroy();
	}

	return fd;
}

void
AutoPipeIstream::_Close() noexcept
{
	CloseInternal();

	Destroy();
}

/*
 * constructor
 *
 */

UnusedIstreamPtr
NewAutoPipeIstream(struct pool *pool, UnusedIstreamPtr input,
		   PipeStock *pipe_stock) noexcept
{
	return NewIstreamPtr<AutoPipeIstream>(*pool, std::move(input), pipe_stock);
}
<|endoftext|>


<commit_before>/*
 * This istream filter removes HTTP chunking.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_dechunk.hxx"
#include "FacadeIstream.hxx"
#include "pool.hxx"

#include <algorithm>

#include <assert.h>
#include <string.h>

enum istream_dechunk_state {
    NONE,
    CLOSED,
    SIZE,
    AFTER_SIZE,
    DATA,
    AFTER_DATA,
    TRAILER,
    TRAILER_DATA,
    EOF_DETECTED
};

class DechunkIstream final : public FacadeIstream {
    enum istream_dechunk_state state;

    size_t remaining_chunk;
    bool had_input, had_output;

    /**
     * Copy chunked data verbatim to handler?
     *
     * @see istream_dechunk_check_verbatim()
     */
    bool verbatim = false;

    /**
     * Was the end-of-file chunk seen at the end of #pending_verbatim?
     */
    bool eof_verbatim;

    /**
     * Number of bytes to be passed to handler verbatim, which have
     * already been parsed but have not yet been consumed by the
     * handler.
     */
    size_t pending_verbatim;

    void (*const eof_callback)(void *ctx);
    void *const callback_ctx;

public:
    DechunkIstream(struct pool &p, struct istream &_input,
                   void (*_eof_callback)(void *ctx), void *_callback_ctx)
        :FacadeIstream(p, _input,
                       MakeIstreamHandler<DechunkIstream>::handler, this),
         state(NONE),
         eof_callback(_eof_callback), callback_ctx(_callback_ctx)
    {
    }

    static DechunkIstream *CheckCast(Istream *i) {
        return dynamic_cast<DechunkIstream *>(i);
    }

    static DechunkIstream *CheckCast(struct istream *i) {
        if (!Istream::CheckClass(*i))
            /* not an Istream (OO) instance */
            return nullptr;

        return CheckCast(&Istream::Cast(*i));
    }

    void SetVerbatim() {
        verbatim = true;
        eof_verbatim = false;
        pending_verbatim = 0;
    }

    void Abort(GError *error);

    /**
     * @return false if the istream_dechunk has been aborted
     * indirectly (by a callback)
     */
    bool EofDetected();

    size_t Feed(const void *data, size_t length);

    /* virtual methods from class Istream */

    off_t GetAvailable(bool partial) override;
    void Read() override;
    void Close() override;

    /* handler */
    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        gcc_unreachable();
    }

    void OnEof();
    void OnError(GError *error);
};

static GQuark
dechunk_quark(void)
{
    return g_quark_from_static_string("dechunk");
}

void
DechunkIstream::Abort(GError *error)
{
    assert(state != EOF_DETECTED && state != CLOSED);
    assert(input.IsDefined());

    state = CLOSED;

    input.ClearAndClose();
    DestroyError(error);
}

bool
DechunkIstream::EofDetected()
{
    assert(input.IsDefined());
    assert(state == TRAILER);
    assert(remaining_chunk == 0);

    state = EOF_DETECTED;

    eof_callback(callback_ctx);

    assert(input.IsDefined());
    assert(state == EOF_DETECTED);

    const ScopePoolRef ref(GetPool() TRACE_ARGS);
    DestroyEof();

    if (state == CLOSED) {
        assert(!input.IsDefined());

        return false;
    } else {
        /* we must deinitialize the "input" after emitting "eof",
           because we must give the callback a chance to call
           dechunk_input_abort() on us; if we'd clear the handler too
           early, we wouldn't receive that event, and
           dechunk_input_data() couldn't change its return value to
           0 */
        assert(input.IsDefined());

        input.ClearHandler();
        return true;
    }
}

size_t
DechunkIstream::Feed(const void *data0, size_t length)
{
    const char *data = (const char *)data0;
    size_t position = 0, digit, size, nbytes;

    assert(input.IsDefined());
    assert(!verbatim || !eof_verbatim);

    if (verbatim)
        /* skip the part that has already been parsed in the last
           invocation, but could not be consumed by the handler */
        position = pending_verbatim;

    had_input = true;

    while (position < length) {
        switch (state) {
        case NONE:
        case SIZE:
            if (data[position] >= '0' && data[position] <= '9') {
                digit = data[position] - '0';
            } else if (data[position] >= 'a' && data[position] <= 'f') {
                digit = data[position] - 'a' + 0xa;
            } else if (data[position] >= 'A' && data[position] <= 'F') {
                digit = data[position] - 'A' + 0xa;
            } else if (state == SIZE) {
                state = AFTER_SIZE;
                ++position;
                continue;
            } else {
                GError *error =
                    g_error_new_literal(dechunk_quark(), 0,
                                        "chunk length expected");
                Abort(error);
                return 0;
            }

            if (state == NONE) {
                state = SIZE;
                remaining_chunk = 0;
            }

            ++position;
            remaining_chunk = remaining_chunk * 0x10 + digit;
            break;

        case CLOSED:
            assert(0);
            break;

        case AFTER_SIZE:
            if (data[position++] == '\n') {
                if (remaining_chunk == 0)
                    state = TRAILER;
                else
                    state = DATA;
            }
            break;

        case DATA:
            assert(remaining_chunk > 0);

            size = length - position;
            if (size > remaining_chunk)
                size = remaining_chunk;

            if (verbatim) {
                /* postpone this data chunk; try to send it all later
                   in one big block */
                nbytes = size;
            } else {
                had_output = true;
                nbytes = InvokeData(data + position, size);
                assert(nbytes <= size);

                if (nbytes == 0)
                    return state == CLOSED ? 0 : position;
            }

            remaining_chunk -= nbytes;
            if (remaining_chunk == 0)
                state = AFTER_DATA;

            position += nbytes;
            break;

        case AFTER_DATA:
            if (data[position] == '\n') {
                state = NONE;
            } else if (data[position] != '\r') {
                GError *error =
                    g_error_new_literal(dechunk_quark(), 0,
                                        "newline expected");
                Abort(error);
                return 0;
            }
            ++position;
            break;

        case TRAILER:
            if (data[position] == '\n') {
                ++position;

                if (verbatim) {
                    /* in "verbatim" mode, we need to send all data
                       before handling the EOF chunk */
                    had_output = true;
                    nbytes = InvokeData(data, position);
                    if (state == CLOSED)
                        return 0;

                    pending_verbatim = position - nbytes;
                    if (pending_verbatim > 0) {
                        /* not everything could be sent; postpone to
                           next call */
                        eof_verbatim = true;
                        return nbytes;
                    }
                }

                return EofDetected() ? position : 0;
            } else if (data[position] == '\r') {
                ++position;
            } else {
                ++position;
                state = TRAILER_DATA;
            }
            break;

        case TRAILER_DATA:
            if (data[position++] == '\n')
                state = TRAILER;
            break;

        case EOF_DETECTED:
            assert(0);
            return 0;
        }
    }

    if (verbatim && position > 0) {
        /* send all chunks in one big block */
        had_output = true;
        nbytes = InvokeData(data, position);
        if (state == CLOSED)
            return 0;

        /* postpone the rest that was not handled; it will not be
           parsed again */
        pending_verbatim = position - nbytes;
        return nbytes;
    }

    return position;
}

/*
 * istream handler
 *
 */

size_t
DechunkIstream::OnData(const void *data, size_t length)
{
    assert(!verbatim || length >= pending_verbatim);

    if (verbatim && eof_verbatim) {
        /* during the last call, the EOF chunk was parsed, but we
           could not handle it yet, because the handler did not
           consume all data yet; try to send the remaining pre-EOF
           data again and then handle the EOF chunk */

        assert(pending_verbatim > 0);

        assert(length >= pending_verbatim);

        had_output = true;
        size_t nbytes = InvokeData(data, pending_verbatim);
        if (nbytes == 0)
            return 0;

        pending_verbatim -= nbytes;
        if (pending_verbatim > 0)
            /* more data needed */
            return nbytes;

        return EofDetected() ? nbytes : 0;
    }

    const ScopePoolRef ref(GetPool() TRACE_ARGS);
    return Feed(data, length);
}

void
DechunkIstream::OnEof()
{
    assert(state != EOF_DETECTED && state != CLOSED);

    state = CLOSED;

    input.Clear();

    GError *error =
        g_error_new_literal(dechunk_quark(), 0,
                            "premature EOF in dechunker");
    DestroyError(error);
}

void
DechunkIstream::OnError(GError *error)
{
    input.Clear();

    if (state != EOF_DETECTED)
        DestroyError(error);
    else
        g_error_free(error);

    state = CLOSED;
}

/*
 * istream implementation
 *
 */

off_t
DechunkIstream::GetAvailable(bool partial)
{
    if (partial && state == DATA)
        return (off_t)remaining_chunk;

    return (off_t)-1;
}

void
DechunkIstream::Read()
{
    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    had_output = false;

    do {
        had_input = false;
        input.Read();
    } while (input.IsDefined() && had_input && !had_output);
}

void
DechunkIstream::Close()
{
    assert(state != EOF_DETECTED);

    state = CLOSED;

    input.ClearHandlerAndClose();
    Destroy();
}

/*
 * constructor
 *
 */

struct istream *
istream_dechunk_new(struct pool *pool, struct istream *input,
                    void (*eof_callback)(void *ctx), void *callback_ctx)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));
    assert(eof_callback != nullptr);

    return NewIstream<DechunkIstream>(*pool, *input,
                                      eof_callback, callback_ctx);
}

bool
istream_dechunk_check_verbatim(struct istream *i)
{
    auto *dechunk = DechunkIstream::CheckCast(i);
    if (dechunk == nullptr)
        /* not a DechunkIstream instance */
        return false;

    dechunk->SetVerbatim();
    return true;
}
<commit_msg>istream/dechunk: move enum into the struct<commit_after>/*
 * This istream filter removes HTTP chunking.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_dechunk.hxx"
#include "FacadeIstream.hxx"
#include "pool.hxx"

#include <algorithm>

#include <assert.h>
#include <string.h>

class DechunkIstream final : public FacadeIstream {
    enum class State {
        NONE,
        CLOSED,
        SIZE,
        AFTER_SIZE,
        DATA,
        AFTER_DATA,
        TRAILER,
        TRAILER_DATA,
        EOF_DETECTED
    } state = State::NONE;

    size_t remaining_chunk;
    bool had_input, had_output;

    /**
     * Copy chunked data verbatim to handler?
     *
     * @see istream_dechunk_check_verbatim()
     */
    bool verbatim = false;

    /**
     * Was the end-of-file chunk seen at the end of #pending_verbatim?
     */
    bool eof_verbatim;

    /**
     * Number of bytes to be passed to handler verbatim, which have
     * already been parsed but have not yet been consumed by the
     * handler.
     */
    size_t pending_verbatim;

    void (*const eof_callback)(void *ctx);
    void *const callback_ctx;

public:
    DechunkIstream(struct pool &p, struct istream &_input,
                   void (*_eof_callback)(void *ctx), void *_callback_ctx)
        :FacadeIstream(p, _input,
                       MakeIstreamHandler<DechunkIstream>::handler, this),
         eof_callback(_eof_callback), callback_ctx(_callback_ctx)
    {
    }

    static DechunkIstream *CheckCast(Istream *i) {
        return dynamic_cast<DechunkIstream *>(i);
    }

    static DechunkIstream *CheckCast(struct istream *i) {
        if (!Istream::CheckClass(*i))
            /* not an Istream (OO) instance */
            return nullptr;

        return CheckCast(&Istream::Cast(*i));
    }

    void SetVerbatim() {
        verbatim = true;
        eof_verbatim = false;
        pending_verbatim = 0;
    }

    void Abort(GError *error);

    /**
     * @return false if the istream_dechunk has been aborted
     * indirectly (by a callback)
     */
    bool EofDetected();

    size_t Feed(const void *data, size_t length);

    /* virtual methods from class Istream */

    off_t GetAvailable(bool partial) override;
    void Read() override;
    void Close() override;

    /* handler */
    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        gcc_unreachable();
    }

    void OnEof();
    void OnError(GError *error);
};

static GQuark
dechunk_quark(void)
{
    return g_quark_from_static_string("dechunk");
}

void
DechunkIstream::Abort(GError *error)
{
    assert(state != State::EOF_DETECTED && state != State::CLOSED);
    assert(input.IsDefined());

    state = State::CLOSED;

    input.ClearAndClose();
    DestroyError(error);
}

bool
DechunkIstream::EofDetected()
{
    assert(input.IsDefined());
    assert(state == State::TRAILER);
    assert(remaining_chunk == 0);

    state = State::EOF_DETECTED;

    eof_callback(callback_ctx);

    assert(input.IsDefined());
    assert(state == State::EOF_DETECTED);

    const ScopePoolRef ref(GetPool() TRACE_ARGS);
    DestroyEof();

    if (state == State::CLOSED) {
        assert(!input.IsDefined());

        return false;
    } else {
        /* we must deinitialize the "input" after emitting "eof",
           because we must give the callback a chance to call
           dechunk_input_abort() on us; if we'd clear the handler too
           early, we wouldn't receive that event, and
           dechunk_input_data() couldn't change its return value to
           0 */
        assert(input.IsDefined());

        input.ClearHandler();
        return true;
    }
}

size_t
DechunkIstream::Feed(const void *data0, size_t length)
{
    const char *data = (const char *)data0;
    size_t position = 0, digit, size, nbytes;

    assert(input.IsDefined());
    assert(!verbatim || !eof_verbatim);

    if (verbatim)
        /* skip the part that has already been parsed in the last
           invocation, but could not be consumed by the handler */
        position = pending_verbatim;

    had_input = true;

    while (position < length) {
        switch (state) {
        case State::NONE:
        case State::SIZE:
            if (data[position] >= '0' && data[position] <= '9') {
                digit = data[position] - '0';
            } else if (data[position] >= 'a' && data[position] <= 'f') {
                digit = data[position] - 'a' + 0xa;
            } else if (data[position] >= 'A' && data[position] <= 'F') {
                digit = data[position] - 'A' + 0xa;
            } else if (state == State::SIZE) {
                state = State::AFTER_SIZE;
                ++position;
                continue;
            } else {
                GError *error =
                    g_error_new_literal(dechunk_quark(), 0,
                                        "chunk length expected");
                Abort(error);
                return 0;
            }

            if (state == State::NONE) {
                state = State::SIZE;
                remaining_chunk = 0;
            }

            ++position;
            remaining_chunk = remaining_chunk * 0x10 + digit;
            break;

        case State::CLOSED:
            assert(0);
            break;

        case State::AFTER_SIZE:
            if (data[position++] == '\n') {
                if (remaining_chunk == 0)
                    state = State::TRAILER;
                else
                    state = State::DATA;
            }
            break;

        case State::DATA:
            assert(remaining_chunk > 0);

            size = length - position;
            if (size > remaining_chunk)
                size = remaining_chunk;

            if (verbatim) {
                /* postpone this data chunk; try to send it all later
                   in one big block */
                nbytes = size;
            } else {
                had_output = true;
                nbytes = InvokeData(data + position, size);
                assert(nbytes <= size);

                if (nbytes == 0)
                    return state == State::CLOSED ? 0 : position;
            }

            remaining_chunk -= nbytes;
            if (remaining_chunk == 0)
                state = State::AFTER_DATA;

            position += nbytes;
            break;

        case State::AFTER_DATA:
            if (data[position] == '\n') {
                state = State::NONE;
            } else if (data[position] != '\r') {
                GError *error =
                    g_error_new_literal(dechunk_quark(), 0,
                                        "newline expected");
                Abort(error);
                return 0;
            }
            ++position;
            break;

        case State::TRAILER:
            if (data[position] == '\n') {
                ++position;

                if (verbatim) {
                    /* in "verbatim" mode, we need to send all data
                       before handling the EOF chunk */
                    had_output = true;
                    nbytes = InvokeData(data, position);
                    if (state == State::CLOSED)
                        return 0;

                    pending_verbatim = position - nbytes;
                    if (pending_verbatim > 0) {
                        /* not everything could be sent; postpone to
                           next call */
                        eof_verbatim = true;
                        return nbytes;
                    }
                }

                return EofDetected() ? position : 0;
            } else if (data[position] == '\r') {
                ++position;
            } else {
                ++position;
                state = State::TRAILER_DATA;
            }
            break;

        case State::TRAILER_DATA:
            if (data[position++] == '\n')
                state = State::TRAILER;
            break;

        case State::EOF_DETECTED:
            assert(0);
            return 0;
        }
    }

    if (verbatim && position > 0) {
        /* send all chunks in one big block */
        had_output = true;
        nbytes = InvokeData(data, position);
        if (state == State::CLOSED)
            return 0;

        /* postpone the rest that was not handled; it will not be
           parsed again */
        pending_verbatim = position - nbytes;
        return nbytes;
    }

    return position;
}

/*
 * istream handler
 *
 */

size_t
DechunkIstream::OnData(const void *data, size_t length)
{
    assert(!verbatim || length >= pending_verbatim);

    if (verbatim && eof_verbatim) {
        /* during the last call, the EOF chunk was parsed, but we
           could not handle it yet, because the handler did not
           consume all data yet; try to send the remaining pre-EOF
           data again and then handle the EOF chunk */

        assert(pending_verbatim > 0);

        assert(length >= pending_verbatim);

        had_output = true;
        size_t nbytes = InvokeData(data, pending_verbatim);
        if (nbytes == 0)
            return 0;

        pending_verbatim -= nbytes;
        if (pending_verbatim > 0)
            /* more data needed */
            return nbytes;

        return EofDetected() ? nbytes : 0;
    }

    const ScopePoolRef ref(GetPool() TRACE_ARGS);
    return Feed(data, length);
}

void
DechunkIstream::OnEof()
{
    assert(state != State::EOF_DETECTED && state != State::CLOSED);

    state = State::CLOSED;

    input.Clear();

    GError *error =
        g_error_new_literal(dechunk_quark(), 0,
                            "premature EOF in dechunker");
    DestroyError(error);
}

void
DechunkIstream::OnError(GError *error)
{
    input.Clear();

    if (state != State::EOF_DETECTED)
        DestroyError(error);
    else
        g_error_free(error);

    state = State::CLOSED;
}

/*
 * istream implementation
 *
 */

off_t
DechunkIstream::GetAvailable(bool partial)
{
    if (partial && state == State::DATA)
        return (off_t)remaining_chunk;

    return (off_t)-1;
}

void
DechunkIstream::Read()
{
    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    had_output = false;

    do {
        had_input = false;
        input.Read();
    } while (input.IsDefined() && had_input && !had_output);
}

void
DechunkIstream::Close()
{
    assert(state != State::EOF_DETECTED);

    state = State::CLOSED;

    input.ClearHandlerAndClose();
    Destroy();
}

/*
 * constructor
 *
 */

struct istream *
istream_dechunk_new(struct pool *pool, struct istream *input,
                    void (*eof_callback)(void *ctx), void *callback_ctx)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));
    assert(eof_callback != nullptr);

    return NewIstream<DechunkIstream>(*pool, *input,
                                      eof_callback, callback_ctx);
}

bool
istream_dechunk_check_verbatim(struct istream *i)
{
    auto *dechunk = DechunkIstream::CheckCast(i);
    if (dechunk == nullptr)
        /* not a DechunkIstream instance */
        return false;

    dechunk->SetVerbatim();
    return true;
}
<|endoftext|>


<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_deflate.hxx"
#include "FacadeIstream.hxx"
#include "pool.hxx"
#include "event/DeferEvent.hxx"
#include "event/Callback.hxx"
#include "util/Cast.hxx"
#include "util/ConstBuffer.hxx"
#include "util/WritableBuffer.hxx"
#include "util/StaticFifoBuffer.hxx"

#include <daemon/log.h>

#include <zlib.h>

#include <assert.h>

class DeflateIstream final : public FacadeIstream {
    bool z_initialized = false, z_stream_end = false;
    z_stream z;
    bool had_input, had_output;
    bool reading;
    StaticFifoBuffer<uint8_t, 4096> buffer;

    /**
     * This callback is used to request more data from the input if an
     * OnData() call did not produce any output.  This tries to
     * prevent stalling the stream.
     */
    DeferEvent defer;

public:
    DeflateIstream(struct pool &pool, struct istream &_input)
        :FacadeIstream(pool, _input,
                       MakeIstreamHandler<DeflateIstream>::handler, this),
         reading(false)
    {
        buffer.Clear();
        defer.Init(MakeSimpleEventCallback(DeflateIstream, OnDeferred), this);
    }

    ~DeflateIstream() {
        defer.Deinit();
    }

    bool InitZlib();

    void DeinitZlib() {
        if (z_initialized) {
            z_initialized = false;
            deflateEnd(&z);
        }
    }

    void Abort(GError *error) {
        DeinitZlib();

        if (HasInput())
            ClearAndCloseInput();

        DestroyError(error);
    }

    /**
     * Submit data from the buffer to our istream handler.
     *
     * @return the number of bytes which were handled, or 0 if the
     * stream was closed
     */
    size_t TryWrite();

    /**
     * Starts to write to the buffer.
     *
     * @return a pointer to the writable buffer, or nullptr if there is no
     * room (our istream handler blocks) or if the stream was closed
     */
    WritableBuffer<void> BufferWrite() {
        auto w = buffer.Write();
        if (w.IsEmpty() && TryWrite() > 0)
            w = buffer.Write();

        return w.ToVoid();
    }

    void TryFlush();

    /**
     * Read from our input until we have submitted some bytes to our
     * istream handler.
     */
    void ForceRead();

    void TryFinish();

    /* virtual methods from class Istream */

    void Read() override {
        if (!buffer.IsEmpty())
            TryWrite();
        else if (HasInput())
            ForceRead();
        else
            TryFinish();
    }

    void Close() override {
        DeinitZlib();

        if (HasInput())
            input.Close();

        Destroy();
    }

    /* handler */
    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        gcc_unreachable();
    }

    void OnEof();
    void OnError(GError *error);

private:
    void OnDeferred() {
        assert(HasInput());

        ForceRead();
    }
};

gcc_const
static GQuark
zlib_quark(void)
{
    return g_quark_from_static_string("zlib");
}

static voidpf z_alloc
(voidpf opaque, uInt items, uInt size)
{
    struct pool *pool = (struct pool *)opaque;

    return p_malloc(pool, items * size);
}

static void
z_free(voidpf opaque, voidpf address)
{
    (void)opaque;
    (void)address;
}

bool
DeflateIstream::InitZlib()
{
    if (z_initialized)
        return true;

    z.zalloc = z_alloc;
    z.zfree = z_free;
    z.opaque = &GetPool();

    int err = deflateInit(&z, Z_DEFAULT_COMPRESSION);
    if (err != Z_OK) {
        GError *error =
            g_error_new(zlib_quark(), err,
                        "deflateInit(Z_FINISH) failed: %d", err);
        Abort(error);
        return false;
    }

    z_initialized = true;
    return true;
}

size_t
DeflateIstream::TryWrite()
{
    auto r = buffer.Read();
    assert(!r.IsEmpty());

    size_t nbytes = InvokeData(r.data, r.size);
    if (nbytes == 0)
        return 0;

    buffer.Consume(nbytes);

    if (nbytes == r.size && !HasInput() && z_stream_end) {
        DeinitZlib();
        DestroyEof();
        return 0;
    }

    return nbytes;
}

inline void
DeflateIstream::TryFlush()
{
    assert(!z_stream_end);

    auto w = BufferWrite();
    if (w.IsEmpty())
        return;

    z.next_out = (Bytef *)w.data;
    z.avail_out = (uInt)w.size;

    z.next_in = nullptr;
    z.avail_in = 0;

    int err = deflate(&z, Z_SYNC_FLUSH);
    if (err != Z_OK) {
        GError *error =
            g_error_new(zlib_quark(), err,
                        "deflate(Z_SYNC_FLUSH) failed: %d", err);
        Abort(error);
        return;
    }

    buffer.Append(w.size - (size_t)z.avail_out);

    if (!buffer.IsEmpty())
        TryWrite();
}

inline
void
DeflateIstream::ForceRead()
{
    assert(!reading);

    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    bool had_input2 = false;
    had_output = false;

    while (1) {
        had_input = false;
        reading = true;
        input.Read();
        reading = false;
        if (!HasInput() || had_output)
            return;

        if (!had_input)
            break;

        had_input2 = true;
    }

    if (had_input2)
        TryFlush();
}

void
DeflateIstream::TryFinish()
{
    assert(!z_stream_end);

    auto w = BufferWrite();
    if (w.IsEmpty())
        return;

    z.next_out = (Bytef *)w.data;
    z.avail_out = (uInt)w.size;

    z.next_in = nullptr;
    z.avail_in = 0;

    int err = deflate(&z, Z_FINISH);
    if (err == Z_STREAM_END)
        z_stream_end = true;
    else if (err != Z_OK) {
        GError *error =
            g_error_new(zlib_quark(), err,
                        "deflate(Z_FINISH) failed: %d", err);
        Abort(error);
        return;
    }

    buffer.Append(w.size - (size_t)z.avail_out);

    if (z_stream_end && buffer.IsEmpty()) {
        DeinitZlib();
        DestroyEof();
    } else
        TryWrite();
}

/*
 * istream handler
 *
 */

size_t
DeflateIstream::OnData(const void *data, size_t length)
{
    assert(HasInput());

    auto w = BufferWrite();
    if (w.size < 64) /* reserve space for end-of-stream marker */
        return 0;

    if (!InitZlib())
        return 0;

    had_input = true;

    if (!reading)
        had_output = false;

    z.next_out = (Bytef *)w.data;
    z.avail_out = (uInt)w.size;

    z.next_in = (Bytef *)const_cast<void *>(data);
    z.avail_in = (uInt)length;

    do {
        auto err = deflate(&z, Z_NO_FLUSH);
        if (err != Z_OK) {
            GError *error =
                g_error_new(zlib_quark(), err,
                            "deflate() failed: %d", err);
            Abort(error);
            return 0;
        }

        size_t nbytes = w.size - (size_t)z.avail_out;
        if (nbytes > 0) {
            had_output = true;
            buffer.Append(nbytes);

            const ScopePoolRef ref(GetPool() TRACE_ARGS);
            TryWrite();

            if (!z_initialized)
                return 0;
        } else
            break;

        w = BufferWrite();
        if (w.size < 64) /* reserve space for end-of-stream marker */
            break;

        z.next_out = (Bytef *)w.data;
        z.avail_out = (uInt)w.size;
    } while (z.avail_in > 0);

    if (!reading && !had_output)
        /* we received data from our input, but we did not produce any
           output (and we're not looping inside ForceRead()) - to
           avoid stalling the stream, trigger the DeferEvent */
        defer.Add();

    return length - (size_t)z.avail_in;
}

void
DeflateIstream::OnEof()
{
    ClearInput();
    defer.Cancel();

    if (!InitZlib())
        return;

    TryFinish();
}

void
DeflateIstream::OnError(GError *error)
{
    ClearInput();

    DeinitZlib();

    DestroyError(error);
}

/*
 * constructor
 *
 */

struct istream *
istream_deflate_new(struct pool *pool, struct istream *input)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    return NewIstream<DeflateIstream>(*pool, *input);
}
<commit_msg>istream/deflate: use deflateInit2()<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_deflate.hxx"
#include "FacadeIstream.hxx"
#include "pool.hxx"
#include "event/DeferEvent.hxx"
#include "event/Callback.hxx"
#include "util/Cast.hxx"
#include "util/ConstBuffer.hxx"
#include "util/WritableBuffer.hxx"
#include "util/StaticFifoBuffer.hxx"

#include <daemon/log.h>

#include <zlib.h>

#include <assert.h>

class DeflateIstream final : public FacadeIstream {
    bool z_initialized = false, z_stream_end = false;
    z_stream z;
    bool had_input, had_output;
    bool reading;
    StaticFifoBuffer<uint8_t, 4096> buffer;

    /**
     * This callback is used to request more data from the input if an
     * OnData() call did not produce any output.  This tries to
     * prevent stalling the stream.
     */
    DeferEvent defer;

public:
    DeflateIstream(struct pool &pool, struct istream &_input)
        :FacadeIstream(pool, _input,
                       MakeIstreamHandler<DeflateIstream>::handler, this),
         reading(false)
    {
        buffer.Clear();
        defer.Init(MakeSimpleEventCallback(DeflateIstream, OnDeferred), this);
    }

    ~DeflateIstream() {
        defer.Deinit();
    }

    bool InitZlib();

    void DeinitZlib() {
        if (z_initialized) {
            z_initialized = false;
            deflateEnd(&z);
        }
    }

    void Abort(GError *error) {
        DeinitZlib();

        if (HasInput())
            ClearAndCloseInput();

        DestroyError(error);
    }

    /**
     * Submit data from the buffer to our istream handler.
     *
     * @return the number of bytes which were handled, or 0 if the
     * stream was closed
     */
    size_t TryWrite();

    /**
     * Starts to write to the buffer.
     *
     * @return a pointer to the writable buffer, or nullptr if there is no
     * room (our istream handler blocks) or if the stream was closed
     */
    WritableBuffer<void> BufferWrite() {
        auto w = buffer.Write();
        if (w.IsEmpty() && TryWrite() > 0)
            w = buffer.Write();

        return w.ToVoid();
    }

    void TryFlush();

    /**
     * Read from our input until we have submitted some bytes to our
     * istream handler.
     */
    void ForceRead();

    void TryFinish();

    /* virtual methods from class Istream */

    void Read() override {
        if (!buffer.IsEmpty())
            TryWrite();
        else if (HasInput())
            ForceRead();
        else
            TryFinish();
    }

    void Close() override {
        DeinitZlib();

        if (HasInput())
            input.Close();

        Destroy();
    }

    /* handler */
    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        gcc_unreachable();
    }

    void OnEof();
    void OnError(GError *error);

private:
    void OnDeferred() {
        assert(HasInput());

        ForceRead();
    }
};

gcc_const
static GQuark
zlib_quark(void)
{
    return g_quark_from_static_string("zlib");
}

static voidpf z_alloc
(voidpf opaque, uInt items, uInt size)
{
    struct pool *pool = (struct pool *)opaque;

    return p_malloc(pool, items * size);
}

static void
z_free(voidpf opaque, voidpf address)
{
    (void)opaque;
    (void)address;
}

bool
DeflateIstream::InitZlib()
{
    if (z_initialized)
        return true;

    z.zalloc = z_alloc;
    z.zfree = z_free;
    z.opaque = &GetPool();

    int err = deflateInit2(&z, Z_DEFAULT_COMPRESSION,
                           Z_DEFLATED, MAX_WBITS, 8,
                           Z_DEFAULT_STRATEGY);
    if (err != Z_OK) {
        GError *error =
            g_error_new(zlib_quark(), err,
                        "deflateInit(Z_FINISH) failed: %d", err);
        Abort(error);
        return false;
    }

    z_initialized = true;
    return true;
}

size_t
DeflateIstream::TryWrite()
{
    auto r = buffer.Read();
    assert(!r.IsEmpty());

    size_t nbytes = InvokeData(r.data, r.size);
    if (nbytes == 0)
        return 0;

    buffer.Consume(nbytes);

    if (nbytes == r.size && !HasInput() && z_stream_end) {
        DeinitZlib();
        DestroyEof();
        return 0;
    }

    return nbytes;
}

inline void
DeflateIstream::TryFlush()
{
    assert(!z_stream_end);

    auto w = BufferWrite();
    if (w.IsEmpty())
        return;

    z.next_out = (Bytef *)w.data;
    z.avail_out = (uInt)w.size;

    z.next_in = nullptr;
    z.avail_in = 0;

    int err = deflate(&z, Z_SYNC_FLUSH);
    if (err != Z_OK) {
        GError *error =
            g_error_new(zlib_quark(), err,
                        "deflate(Z_SYNC_FLUSH) failed: %d", err);
        Abort(error);
        return;
    }

    buffer.Append(w.size - (size_t)z.avail_out);

    if (!buffer.IsEmpty())
        TryWrite();
}

inline
void
DeflateIstream::ForceRead()
{
    assert(!reading);

    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    bool had_input2 = false;
    had_output = false;

    while (1) {
        had_input = false;
        reading = true;
        input.Read();
        reading = false;
        if (!HasInput() || had_output)
            return;

        if (!had_input)
            break;

        had_input2 = true;
    }

    if (had_input2)
        TryFlush();
}

void
DeflateIstream::TryFinish()
{
    assert(!z_stream_end);

    auto w = BufferWrite();
    if (w.IsEmpty())
        return;

    z.next_out = (Bytef *)w.data;
    z.avail_out = (uInt)w.size;

    z.next_in = nullptr;
    z.avail_in = 0;

    int err = deflate(&z, Z_FINISH);
    if (err == Z_STREAM_END)
        z_stream_end = true;
    else if (err != Z_OK) {
        GError *error =
            g_error_new(zlib_quark(), err,
                        "deflate(Z_FINISH) failed: %d", err);
        Abort(error);
        return;
    }

    buffer.Append(w.size - (size_t)z.avail_out);

    if (z_stream_end && buffer.IsEmpty()) {
        DeinitZlib();
        DestroyEof();
    } else
        TryWrite();
}

/*
 * istream handler
 *
 */

size_t
DeflateIstream::OnData(const void *data, size_t length)
{
    assert(HasInput());

    auto w = BufferWrite();
    if (w.size < 64) /* reserve space for end-of-stream marker */
        return 0;

    if (!InitZlib())
        return 0;

    had_input = true;

    if (!reading)
        had_output = false;

    z.next_out = (Bytef *)w.data;
    z.avail_out = (uInt)w.size;

    z.next_in = (Bytef *)const_cast<void *>(data);
    z.avail_in = (uInt)length;

    do {
        auto err = deflate(&z, Z_NO_FLUSH);
        if (err != Z_OK) {
            GError *error =
                g_error_new(zlib_quark(), err,
                            "deflate() failed: %d", err);
            Abort(error);
            return 0;
        }

        size_t nbytes = w.size - (size_t)z.avail_out;
        if (nbytes > 0) {
            had_output = true;
            buffer.Append(nbytes);

            const ScopePoolRef ref(GetPool() TRACE_ARGS);
            TryWrite();

            if (!z_initialized)
                return 0;
        } else
            break;

        w = BufferWrite();
        if (w.size < 64) /* reserve space for end-of-stream marker */
            break;

        z.next_out = (Bytef *)w.data;
        z.avail_out = (uInt)w.size;
    } while (z.avail_in > 0);

    if (!reading && !had_output)
        /* we received data from our input, but we did not produce any
           output (and we're not looping inside ForceRead()) - to
           avoid stalling the stream, trigger the DeferEvent */
        defer.Add();

    return length - (size_t)z.avail_in;
}

void
DeflateIstream::OnEof()
{
    ClearInput();
    defer.Cancel();

    if (!InitZlib())
        return;

    TryFinish();
}

void
DeflateIstream::OnError(GError *error)
{
    ClearInput();

    DeinitZlib();

    DestroyError(error);
}

/*
 * constructor
 *
 */

struct istream *
istream_deflate_new(struct pool *pool, struct istream *input)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    return NewIstream<DeflateIstream>(*pool, *input);
}
<|endoftext|>


<commit_before>// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
#include <typeinfo>

// CHECK: _ZTS1B = constant
// CHECK: _ZTS1A = weak_odr constant
// CHECK: _ZTI1A = weak_odr constant
// CHECK: _ZTI1B = constant
// CHECK: _ZTSP1C = internal constant
// CHECK: _ZTS1C = internal constant
// CHECK: _ZTI1C = internal constant
// CHECK: _ZTIP1C = internal constant
// CHECK: _ZTSPP1C = internal constant
// CHECK: _ZTIPP1C = internal constant
// CHECK: _ZTSM1Ci = internal constant
// CHECK: _ZTIM1Ci = internal constant
// CHECK: _ZTSPM1Ci = internal constant
// CHECK: _ZTIPM1Ci = internal constant
// CHECK: _ZTSM1CS_ = internal constant
// CHECK: _ZTIM1CS_ = internal constant
// CHECK: _ZTSM1CPS_ = internal constant
// CHECK: _ZTIM1CPS_ = internal constant
// CHECK: _ZTSM1A1C = internal constant
// CHECK: _ZTIM1A1C = internal constant
// CHECK: _ZTSM1AP1C = internal constant
// CHECK: _ZTIM1AP1C = internal constant

// A has no key function, so its RTTI data should be weak_odr.
struct A { };

// B has a key function defined in the translation unit, so the RTTI data should
// be emitted in this translation unit and have external linkage.
struct B : A {
  virtual void f();
};
void B::f() { }

// C is an incomplete class type, so any direct or indirect pointer types should have
// internal linkage, as should the type info for C itself (FIXME).
struct C;

void f() {
  (void)typeid(C*);
  (void)typeid(C**);
  (void)typeid(int C::*);
  (void)typeid(int C::**);
  (void)typeid(C C::*);
  (void)typeid(C *C::*);
  (void)typeid(C A::*);
  (void)typeid(C* A::*);

}

<commit_msg>Add tests for structs inside anonymous namespaces.<commit_after>// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
#include <typeinfo>

// CHECK: _ZTS1B = constant
// CHECK: _ZTS1A = weak_odr constant
// CHECK: _ZTI1A = weak_odr constant
// CHECK: _ZTI1B = constant
// CHECK: _ZTSP1C = internal constant
// CHECK: _ZTS1C = internal constant
// CHECK: _ZTI1C = internal constant
// CHECK: _ZTIP1C = internal constant
// CHECK: _ZTSPP1C = internal constant
// CHECK: _ZTIPP1C = internal constant
// CHECK: _ZTSM1Ci = internal constant
// CHECK: _ZTIM1Ci = internal constant
// CHECK: _ZTSPM1Ci = internal constant
// CHECK: _ZTIPM1Ci = internal constant
// CHECK: _ZTSM1CS_ = internal constant
// CHECK: _ZTIM1CS_ = internal constant
// CHECK: _ZTSM1CPS_ = internal constant
// CHECK: _ZTIM1CPS_ = internal constant
// CHECK: _ZTSM1A1C = internal constant
// CHECK: _ZTIM1A1C = internal constant
// CHECK: _ZTSM1AP1C = internal constant
// CHECK: _ZTIM1AP1C = internal constant

// CHECK: _ZTSN12_GLOBAL__N_11DE = internal constant
// CHECK: _ZTIN12_GLOBAL__N_11DE = internal constant
// CHECK: _ZTSPN12_GLOBAL__N_11DE = internal constant
// CHECK: _ZTIPN12_GLOBAL__N_11DE = internal constant

// A has no key function, so its RTTI data should be weak_odr.
struct A { };

// B has a key function defined in the translation unit, so the RTTI data should
// be emitted in this translation unit and have external linkage.
struct B : A {
  virtual void f();
};
void B::f() { }

// C is an incomplete class type, so any direct or indirect pointer types should have
// internal linkage, as should the type info for C itself (FIXME).
struct C;

void t1() {
  (void)typeid(C*);
  (void)typeid(C**);
  (void)typeid(int C::*);
  (void)typeid(int C::**);
  (void)typeid(C C::*);
  (void)typeid(C *C::*);
  (void)typeid(C A::*);
  (void)typeid(C* A::*);
}

namespace {
  // D is inside an anonymous namespace, so all type information related to D should have
  // internal linkage.
  struct D { };
};

void t2() {
  (void)typeid(D);
  (void)typeid(D *);

}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <print.hpp>
#include <system.hpp>
#include <string.hpp>

int main(){
    char input_buffer[64];

    while(true){
        print("thor> ");

        auto c = read_input(input_buffer, 63);

        if(input_buffer[c-1] == '\n'){
            if(c == 1){
                print_line();
                continue;
            }

            input_buffer[c] = '\0';

            if(str_equals(input_buffer, "exit")){
                exit(0);
            } else if(str_equals(input_buffer, "long")){
                //TODO Remove this function when exec system is complete
                exec_and_wait("long");
            } else if(str_equals(input_buffer, "sleep")){
                //TODO Once better infrastrucure, parse command line and sleep the
                //correct number of milliseconds
                sleep_ms(5000);
            } else {
                print_line("Unknown command");
            }
        } else {
            //TODO Once in good shape, just append to current input buffer
        }

    }
}<commit_msg>Fix parsing<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <print.hpp>
#include <system.hpp>
#include <string.hpp>

int main(){
    char input_buffer[64];

    while(true){
        print("thor> ");

        auto c = read_input(input_buffer, 63);

        if(input_buffer[c-1] == '\n'){
            if(c == 1){
                print_line();
                continue;
            }

            input_buffer[c-1] = '\0';

            if(str_equals(input_buffer, "exit")){
                exit(0);
            } else if(str_equals(input_buffer, "long")){
                //TODO Remove this function when exec system is complete
                exec_and_wait("long");
            } else if(str_equals(input_buffer, "sleep")){
                //TODO Once better infrastrucure, parse command line and sleep the
                //correct number of milliseconds
                sleep_ms(5000);
            } else {
                print_line("Unknown command");
            }
        } else {
            //TODO Once in good shape, just append to current input buffer
        }

    }
}<|endoftext|>


<commit_before>/*
 *  niicomplex.cpp
 *
 *  Created by Tobias Wood on 03/06/2015.
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <getopt.h>
#include <iostream>
#include <random>
#include <functional>

#include "itkImage.h"
#include "itkComplexToPhaseImageFilter.h"
#include "itkComplexToModulusImageFilter.h"
#include "itkComplexToRealImageFilter.h"
#include "itkComplexToImaginaryImageFilter.h"
#include "itkComposeImageFilter.h"
#include "itkMagnitudeAndPhaseToComplexImageFilter.h"

#include "Util.h"
#include "Types.h"

using namespace std;

const string usage {
"Usage is: qcomplex [input options] [output options] [other options] \n\
\n\
Input is specified with lower case letters. One of the following\n\
combinations must be specified:\n\
	-m mag_image -p phase_image\n\
	-r real_image -i imaginary_image\n\
	-x complex_image\n\
\n\
Output is specified with upper case letters. One or more of the\n\
following can be specified:\n\
	-M : Output a magnitude image\n\
	-P : Output a phase image\n\
	-R : Output a real image\n\
	-I : Output an imaginary image\n\
	-X : Output a complex image\n\
\n\
Other options:\n\
	--double : Use double precision instead of float\n\
	--fixge  : Fix alternate slice problem with GE data.\n\
\n\
Example:\n\
	qicomplex -m mag.nii -p phase.nii -R real.nii -I imag.nii\n"
};
int verbose = false, use_double = false, fixge = false;
const struct option long_options[] =
{
	{"help", no_argument, 0, 'h'},
	{"verbose", no_argument, 0, 'v'},
	{"double", no_argument, &use_double, 1},
	{"fixge", no_argument, &fixge, 1},
	{0, 0, 0, 0}
};
const char* short_options = "hvm:M:p:P:r:R:i:I:x:X:";
int c, index_ptr = 0;

template<typename TPixel> void Run(int argc, char **argv) {
	typedef itk::Image<TPixel, 4>          TImage;
	typedef itk::Image<complex<TPixel>, 4> TXImage;
	typedef itk::ImageFileReader<TImage>   TReader;
	typedef itk::ImageFileReader<TXImage>  TXReader;
	typedef itk::ImageFileWriter<TImage>   TWriter;
	typedef itk::ImageFileWriter<TXImage>  TXWriter;

	typename TImage::Pointer img1 = ITK_NULLPTR, img2 = ITK_NULLPTR;
	typename TXImage::Pointer imgX = ITK_NULLPTR;

	if (verbose) cout << "Reading input files" << endl;
	bool ri = false, x = false;
	optind = 1;
	while ((c = getopt(argc, argv, short_options)) != -1) {
		switch (c) {
			case 'r':
				ri = true;
			case 'm': {
				auto read = TReader::New();
				read->SetFileName(optarg);
				read->Update();
				img1 = read->GetOutput();
			} break;
			case 'i':
				ri = true;
			case 'p': {
				auto read = TReader::New();
				read->SetFileName(optarg);
				read->Update();
				img2 = read->GetOutput();
			} break;
			case 'x': {
				x = true;
				typename TXReader::Pointer readX = TXReader::New();
				readX->SetFileName(optarg);
				readX->Update();
				imgX = readX->GetOutput();
			} break;
			default: break;
		}
	}

	if (x) {
		// Nothing to see here
	} else if (ri) {
		if (!(img1 && img2)) {
			throw(runtime_error("Must set real and imaginary inputs"));
		}
		if (verbose) cout << "Combining real and imaginary input" << endl;
		auto compose = itk::ComposeImageFilter<TImage, TXImage>::New();
		compose->SetInput(0, img1);
		compose->SetInput(1, img2);
		compose->Update();
		imgX = compose->GetOutput();
	} else {
		if (!(img1 && img2)) {
			throw(runtime_error("Must set magnitude and phase inputs"));
		}
		if (verbose) cout << "Combining magnitude and phase input" << endl;
		auto compose = itk::MagnitudeAndPhaseToComplexImageFilter<TImage, TImage, TXImage>::New();
		compose->SetInput(0, img1);
		compose->SetInput(1, img2);
		compose->Update();
		imgX = compose->GetOutput();
	}

	if (verbose) cout << "Writing output files" << endl;
	typename TWriter::Pointer write = TWriter::New();
	optind = 1;
	while ((c = getopt(argc, argv, short_options)) != -1) {
		switch (c) {
			case 'M': {
				auto o = itk::ComplexToModulusImageFilter<TXImage, TImage>::New();
				o->SetInput(imgX);
				write->SetFileName(optarg);
				write->SetInput(o->GetOutput());
				write->Update();
				if (verbose) cout << "Wrote magnitude image " + string(optarg) << endl;
			} break;
			case 'P': {
				auto o = itk::ComplexToPhaseImageFilter<TXImage, TImage>::New();
				o->SetInput(imgX);
				write->SetFileName(optarg);
				write->SetInput(o->GetOutput());
				write->Update();
				if (verbose) cout << "Wrote phase image " + string(optarg) << endl;
			} break;
			case 'R': {
				auto o = itk::ComplexToRealImageFilter<TXImage, TImage>::New();
				o->SetInput(imgX);
				write->SetFileName(optarg);
				write->SetInput(o->GetOutput());
				write->Update();
				if (verbose) cout << "Wrote real image " + string(optarg) << endl;
			} break;
			case 'I': {
				auto o = itk::ComplexToImaginaryImageFilter<TXImage, TImage>::New();
				o->SetInput(imgX);
				write->SetFileName(optarg);
				write->SetInput(o->GetOutput());
				write->Update();
				if (verbose) cout << "Wrote imaginary image " + string(optarg) << endl;
			} break;
			case 'X': {
				auto writeX = TXWriter::New();
				writeX->SetFileName(optarg);
				writeX->SetInput(imgX);
				writeX->Update();
				if (verbose) cout << "Wrote complex image " + string(optarg) << endl;
			} break;
			default: break;
		}
	}
}

int main(int argc, char **argv) {
	// Do one pass for the general options
	bool have_some_options = false;
	while ((c = getopt_long(argc, argv, short_options, long_options, &index_ptr)) != -1) {
		switch (c) {
			case 'v': verbose = true; break;
			case 'h':
				cout << usage << endl;
				return EXIT_SUCCESS;
			case 0: break; // A flag
			case 'm': case 'M': case 'p': case 'P':
			case 'r': case 'R': case 'i': case 'I':
			case 'x': case 'X':
				have_some_options = true;
				break;
			case '?': // getopt will print an error message
				return EXIT_FAILURE;
			default:
			cout << "Unhandled option " << string(1, c) << endl;
			return EXIT_FAILURE;
		}
	}

	if (!have_some_options) {
		cout << usage << endl;
		return EXIT_FAILURE;
	}

	if (use_double) {
		if (verbose) cout << "Using double precision" << endl;
		Run<double>(argc, argv);
	} else {
		if (verbose) cout << "Using float precision" << endl;
		Run<float>(argc, argv);
	}

	return EXIT_SUCCESS;
}
<commit_msg>Removed fixge option from the usage string as it is not currently implemented.<commit_after>/*
 *  niicomplex.cpp
 *
 *  Created by Tobias Wood on 03/06/2015.
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <getopt.h>
#include <iostream>
#include <random>
#include <functional>

#include "itkImage.h"
#include "itkComplexToPhaseImageFilter.h"
#include "itkComplexToModulusImageFilter.h"
#include "itkComplexToRealImageFilter.h"
#include "itkComplexToImaginaryImageFilter.h"
#include "itkComposeImageFilter.h"
#include "itkMagnitudeAndPhaseToComplexImageFilter.h"

#include "Util.h"
#include "Types.h"

using namespace std;

const string usage {
"Usage is: qcomplex [input options] [output options] [other options] \n\
\n\
Input is specified with lower case letters. One of the following\n\
combinations must be specified:\n\
	-m mag_image -p phase_image\n\
	-r real_image -i imaginary_image\n\
	-x complex_image\n\
\n\
Output is specified with upper case letters. One or more of the\n\
following can be specified:\n\
	-M : Output a magnitude image\n\
	-P : Output a phase image\n\
	-R : Output a real image\n\
	-I : Output an imaginary image\n\
	-X : Output a complex image\n\
\n\
Other options:\n\
	--double : Use double precision instead of float\n\
\n\
Example:\n\
	qicomplex -m mag.nii -p phase.nii -R real.nii -I imag.nii\n"
};
int verbose = false, use_double = false, fixge = false;
const struct option long_options[] =
{
	{"help", no_argument, 0, 'h'},
	{"verbose", no_argument, 0, 'v'},
	{"double", no_argument, &use_double, 1},
	{"fixge", no_argument, &fixge, 1},
	{0, 0, 0, 0}
};
const char* short_options = "hvm:M:p:P:r:R:i:I:x:X:";
int c, index_ptr = 0;

template<typename TPixel> void Run(int argc, char **argv) {
	typedef itk::Image<TPixel, 4>          TImage;
	typedef itk::Image<complex<TPixel>, 4> TXImage;
	typedef itk::ImageFileReader<TImage>   TReader;
	typedef itk::ImageFileReader<TXImage>  TXReader;
	typedef itk::ImageFileWriter<TImage>   TWriter;
	typedef itk::ImageFileWriter<TXImage>  TXWriter;

	typename TImage::Pointer img1 = ITK_NULLPTR, img2 = ITK_NULLPTR;
	typename TXImage::Pointer imgX = ITK_NULLPTR;

	if (verbose) cout << "Reading input files" << endl;
	bool ri = false, x = false;
	optind = 1;
	while ((c = getopt(argc, argv, short_options)) != -1) {
		switch (c) {
			case 'r':
				ri = true;
			case 'm': {
				auto read = TReader::New();
				read->SetFileName(optarg);
				read->Update();
				img1 = read->GetOutput();
			} break;
			case 'i':
				ri = true;
			case 'p': {
				auto read = TReader::New();
				read->SetFileName(optarg);
				read->Update();
				img2 = read->GetOutput();
			} break;
			case 'x': {
				x = true;
				typename TXReader::Pointer readX = TXReader::New();
				readX->SetFileName(optarg);
				readX->Update();
				imgX = readX->GetOutput();
			} break;
			default: break;
		}
	}

	if (x) {
		// Nothing to see here
	} else if (ri) {
		if (!(img1 && img2)) {
			throw(runtime_error("Must set real and imaginary inputs"));
		}
		if (verbose) cout << "Combining real and imaginary input" << endl;
		auto compose = itk::ComposeImageFilter<TImage, TXImage>::New();
		compose->SetInput(0, img1);
		compose->SetInput(1, img2);
		compose->Update();
		imgX = compose->GetOutput();
	} else {
		if (!(img1 && img2)) {
			throw(runtime_error("Must set magnitude and phase inputs"));
		}
		if (verbose) cout << "Combining magnitude and phase input" << endl;
		auto compose = itk::MagnitudeAndPhaseToComplexImageFilter<TImage, TImage, TXImage>::New();
		compose->SetInput(0, img1);
		compose->SetInput(1, img2);
		compose->Update();
		imgX = compose->GetOutput();
	}

	if (verbose) cout << "Writing output files" << endl;
	typename TWriter::Pointer write = TWriter::New();
	optind = 1;
	while ((c = getopt(argc, argv, short_options)) != -1) {
		switch (c) {
			case 'M': {
				auto o = itk::ComplexToModulusImageFilter<TXImage, TImage>::New();
				o->SetInput(imgX);
				write->SetFileName(optarg);
				write->SetInput(o->GetOutput());
				write->Update();
				if (verbose) cout << "Wrote magnitude image " + string(optarg) << endl;
			} break;
			case 'P': {
				auto o = itk::ComplexToPhaseImageFilter<TXImage, TImage>::New();
				o->SetInput(imgX);
				write->SetFileName(optarg);
				write->SetInput(o->GetOutput());
				write->Update();
				if (verbose) cout << "Wrote phase image " + string(optarg) << endl;
			} break;
			case 'R': {
				auto o = itk::ComplexToRealImageFilter<TXImage, TImage>::New();
				o->SetInput(imgX);
				write->SetFileName(optarg);
				write->SetInput(o->GetOutput());
				write->Update();
				if (verbose) cout << "Wrote real image " + string(optarg) << endl;
			} break;
			case 'I': {
				auto o = itk::ComplexToImaginaryImageFilter<TXImage, TImage>::New();
				o->SetInput(imgX);
				write->SetFileName(optarg);
				write->SetInput(o->GetOutput());
				write->Update();
				if (verbose) cout << "Wrote imaginary image " + string(optarg) << endl;
			} break;
			case 'X': {
				auto writeX = TXWriter::New();
				writeX->SetFileName(optarg);
				writeX->SetInput(imgX);
				writeX->Update();
				if (verbose) cout << "Wrote complex image " + string(optarg) << endl;
			} break;
			default: break;
		}
	}
}

int main(int argc, char **argv) {
	// Do one pass for the general options
	bool have_some_options = false;
	while ((c = getopt_long(argc, argv, short_options, long_options, &index_ptr)) != -1) {
		switch (c) {
			case 'v': verbose = true; break;
			case 'h':
				cout << usage << endl;
				return EXIT_SUCCESS;
			case 0: break; // A flag
			case 'm': case 'M': case 'p': case 'P':
			case 'r': case 'R': case 'i': case 'I':
			case 'x': case 'X':
				have_some_options = true;
				break;
			case '?': // getopt will print an error message
				return EXIT_FAILURE;
			default:
			cout << "Unhandled option " << string(1, c) << endl;
			return EXIT_FAILURE;
		}
	}

	if (!have_some_options) {
		cout << usage << endl;
		return EXIT_FAILURE;
	}

	if (use_double) {
		if (verbose) cout << "Using double precision" << endl;
		Run<double>(argc, argv);
	} else {
		if (verbose) cout << "Using float precision" << endl;
		Run<float>(argc, argv);
	}

	return EXIT_SUCCESS;
}
<|endoftext|>