<commit_before>//=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly code to machine code -//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file implements the WebAssemblyMCCodeEmitter class.
///
//===----------------------------------------------------------------------===//

#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

#define DEBUG_TYPE "mccodeemitter"

namespace {
class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
  const MCInstrInfo &MCII;
  const MCRegisterInfo &MRI;
  const MCContext &Ctx;

public:
  WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
                           MCContext &ctx)
      : MCII(mcii), MRI(mri), Ctx(ctx) {}

  ~WebAssemblyMCCodeEmitter() override {}

  /// TableGen'erated function for getting the binary encoding for an
  /// instruction.
  uint64_t getBinaryCodeForInstr(const MCInst &MI,
                                 SmallVectorImpl<MCFixup> &Fixups,
                                 const MCSubtargetInfo &STI) const;

  /// Return binary encoding of operand. If the machine operand requires
  /// relocation, record the relocation and return zero.
  unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
                             SmallVectorImpl<MCFixup> &Fixups,
                             const MCSubtargetInfo &STI) const;

  uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op,
                            SmallVectorImpl<MCFixup> &Fixups,
                            const MCSubtargetInfo &STI) const;

  void encodeInstruction(const MCInst &MI, raw_ostream &OS,
                         SmallVectorImpl<MCFixup> &Fixups,
                         const MCSubtargetInfo &STI) const override;
};
} // end anonymous namespace

MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII,
                                                    const MCRegisterInfo &MRI,
                                                    MCContext &Ctx) {
  return new WebAssemblyMCCodeEmitter(MCII, MRI, Ctx);
}

unsigned WebAssemblyMCCodeEmitter::getMachineOpValue(
    const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups,
    const MCSubtargetInfo &STI) const {
  if (MO.isReg())
    return MRI.getEncodingValue(MO.getReg());
  if (MO.isImm())
    return static_cast<unsigned>(MO.getImm());

  assert(MO.isExpr());

  const MCExpr *Expr = MO.getExpr();

  assert(Expr->getKind() == MCExpr::SymbolRef);

  assert(false && "FIXME: not implemented yet");

  return 0;
}

void WebAssemblyMCCodeEmitter::encodeInstruction(
    const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
    const MCSubtargetInfo &STI) const {
  assert(false && "FIXME: not implemented yet");
}

// Encode WebAssembly Memory Operand
uint64_t
WebAssemblyMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op,
                                           SmallVectorImpl<MCFixup> &Fixups,
                                           const MCSubtargetInfo &STI) const {
  assert(false && "FIXME: not implemented yet");
  return 0;
}

#include "WebAssemblyGenMCCodeEmitter.inc"
<commit_msg>Fix unused variable warning in release builds. NFC.<commit_after>//=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly code to machine code -//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file implements the WebAssemblyMCCodeEmitter class.
///
//===----------------------------------------------------------------------===//

#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

#define DEBUG_TYPE "mccodeemitter"

namespace {
class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
  const MCInstrInfo &MCII;
  const MCRegisterInfo &MRI;
  const MCContext &Ctx;

public:
  WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
                           MCContext &ctx)
      : MCII(mcii), MRI(mri), Ctx(ctx) {}

  ~WebAssemblyMCCodeEmitter() override {}

  /// TableGen'erated function for getting the binary encoding for an
  /// instruction.
  uint64_t getBinaryCodeForInstr(const MCInst &MI,
                                 SmallVectorImpl<MCFixup> &Fixups,
                                 const MCSubtargetInfo &STI) const;

  /// Return binary encoding of operand. If the machine operand requires
  /// relocation, record the relocation and return zero.
  unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
                             SmallVectorImpl<MCFixup> &Fixups,
                             const MCSubtargetInfo &STI) const;

  uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op,
                            SmallVectorImpl<MCFixup> &Fixups,
                            const MCSubtargetInfo &STI) const;

  void encodeInstruction(const MCInst &MI, raw_ostream &OS,
                         SmallVectorImpl<MCFixup> &Fixups,
                         const MCSubtargetInfo &STI) const override;
};
} // end anonymous namespace

MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII,
                                                    const MCRegisterInfo &MRI,
                                                    MCContext &Ctx) {
  return new WebAssemblyMCCodeEmitter(MCII, MRI, Ctx);
}

unsigned WebAssemblyMCCodeEmitter::getMachineOpValue(
    const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups,
    const MCSubtargetInfo &STI) const {
  if (MO.isReg())
    return MRI.getEncodingValue(MO.getReg());
  if (MO.isImm())
    return static_cast<unsigned>(MO.getImm());

  assert(MO.isExpr());

  assert(MO.getExpr()->getKind() == MCExpr::SymbolRef);

  assert(false && "FIXME: not implemented yet");

  return 0;
}

void WebAssemblyMCCodeEmitter::encodeInstruction(
    const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
    const MCSubtargetInfo &STI) const {
  assert(false && "FIXME: not implemented yet");
}

// Encode WebAssembly Memory Operand
uint64_t
WebAssemblyMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op,
                                           SmallVectorImpl<MCFixup> &Fixups,
                                           const MCSubtargetInfo &STI) const {
  assert(false && "FIXME: not implemented yet");
  return 0;
}

#include "WebAssemblyGenMCCodeEmitter.inc"
<|endoftext|>


<commit_before>#include <Python.h>
#include <vector>

struct peak{
   char* chr;
   int chr_start;
   int chr_end;
   float score;
   float signal;
   float q_value;
   float error_rate;
};

static PyObject *
ens_main(PyObject *self, PyObject *args){

   PyObject *peaks_data = (PyObject*)PyList_New(0);
   PyObject *error_data = (PyObject*)PyList_New(0);

   PyObject **peak_containor = (PyObject**)PyList_New(2);
   PyObject *dict_containor = (PyObject*)PyDict_New();

   double error_containor[2];
   std::vector<peak> peak_vec;
   peak* peak_element;

   char* chr;
   char* chr_start;
   char* chr_end;
   char* signal;
   char* q_value;
   char* score;
   char* error_rate;

   //////// Python Object to C++ Local variable /////////
   if(!PyArg_ParseTuple(args, "O!O!",&PyList_Type,&peaks_data, &PyList_Type, &error_data))
      return NULL;

   //for ( int i = 0; i < PyList_Size(peaks_data); i++){
     // printf("%d th output file process::::::\n" , i);
     // peak_containor[i] = PyList_GetItem(peaks_data,i);
      //error_containor = PyFloat_AsDouble(PyList_GetItem(error_data,i));
   for ( int i = 0; i < PyList_Size(peaks_data); i++){
      peak_containor[i] = PyList_GetItem(peaks_data,i);
      error_containor[i] = PyFloat_AsDouble(PyList_GetItem(error_data,i));
   }
   for ( int i = 0; i < PyList_Size(peaks_data); i++){
      for ( int j = 0 ; j < PyList_Size(peak_containor[i]) ; j++){
         dict_containor = PyList_GetItem(peak_containor[i], j);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"region_s"), "s", &chr_start);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"region_e"), "s", &chr_end);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"chr"), "s", &chr);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"score"), "s", &score);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"signalValue"), "s", &signal);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"qValue"),"s",&q_value);

         peak_element = new peak;
         peak_element->chr = chr;
         peak_element->chr_start = atoi(chr_start);
         peak_element->chr_end = atoi(chr_end);
         peak_element->score = atof(score);
         peak_element->signal = atof(signal);
         peak_element->q_value = atof(q_value);
         peak_element->error_rate = error_containor[i];

         peak_vec.push_back(*peak_element);
         printf("now parse %d`s of peak , signal = %f\n", peak_vec.size(), peak_element->signal);
      }
   }
   //////// C++ value to Python Object /////////////////
   return Py_BuildValue("i",1);
}

static PyMethodDef ensembleMethods[] = {
   {"ensembler", ens_main, METH_VARARGS, "main flow of ensembler."},
   {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initensemble(void){
   (void) Py_InitModule("ensemble",ensembleMethods);
}

int main(int argc, char *argv[]){
   Py_SetProgramName(argv[0]);
   Py_Initialize();
   initensemble();
   return 0;
}
<commit_msg>one by one<commit_after>#include <Python.h>
#include <vector>

struct peak{
   char* chr;
   int chr_start;
   int chr_end;
   float score;
   float signal;
   float q_value;
   float error_rate;
};

static PyObject *
ens_main(PyObject *self, PyObject *args){

   PyObject *peaks_data = (PyObject*)PyList_New(0);
   PyObject *error_data = (PyObject*)PyList_New(0);

   PyObject *peak_containor = (PyObject*)PyList_New(0);
   PyObject *dict_containor = (PyObject*)PyDict_New();

   double error_containor;
   std::vector<peak> peak_vec;
   peak* peak_element;

   char* chr;
   char* chr_start;
   char* chr_end;
   char* signal;
   char* q_value;
   char* score;
   char* error_rate;

   //////// Python Object to C++ Local variable /////////
   if(!PyArg_ParseTuple(args, "O!O!",&PyList_Type,&peaks_data, &PyList_Type, &error_data))
      return NULL;

   for ( int i = 0; i < PyList_Size(peaks_data); i++){
      printf("%d th output file process::::::\n" , i);
      peak_containor = PyList_GetItem(peaks_data,i);
      error_containor = PyFloat_AsDouble(PyList_GetItem(error_data,i));

      for ( int j = 0 ; j < PyList_Size(peak_containor) ; j++){
         dict_containor = PyList_GetItem(peak_containor, j);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"region_s"), "s", &chr_start);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"region_e"), "s", &chr_end);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"chr"), "s", &chr);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"score"), "s", &score);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"signalValue"), "s", &signal);
         PyArg_Parse(PyDict_GetItemString(dict_containor,"qValue"),"s",&q_value);

         peak_element = new peak;
         peak_element->chr = chr;
         peak_element->chr_start = atoi(chr_start);
         peak_element->chr_end = atoi(chr_end);
         peak_element->score = atof(score);
         peak_element->signal = atof(signal);
         peak_element->q_value = atof(q_value);
         peak_element->error_rate = error_containor;

         peak_vec.push_back(*peak_element);
         printf("now parse %d`s of peak , signal = %f\n", peak_vec.size(), peak_element->signal);
      }
   }
   //////// C++ value to Python Object /////////////////
   return Py_BuildValue("i",1);
}

static PyMethodDef ensembleMethods[] = {
   {"ensembler", ens_main, METH_VARARGS, "main flow of ensembler."},
   {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initensemble(void){
   (void) Py_InitModule("ensemble",ensembleMethods);
}

int main(int argc, char *argv[]){
   Py_SetProgramName(argv[0]);
   Py_Initialize();
   initensemble();
   return 0;
}
<|endoftext|>


<commit_before>#ifndef INCLUDE_AL_CSVREADER_HPP
#define INCLUDE_AL_CSVREADER_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2012. The Regents of the University of California.
	All rights reserved.

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

		Redistributions of source code must retain the above copyright notice,
		this list of conditions and the following disclaimer.

		Redistributions in binary form must reproduce the above copyright
		notice, this list of conditions and the following disclaimer in the
		documentation and/or other materials provided with the distribution.

		Neither the name of the University of California nor the names of its
		contributors may be used to endorse or promote products derived from
		this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.

	File description:
	CSV File reader

	File author(s):
	Andres Cabrera mantaraya36@gmail.com 2017
*/

#include <vector>
#include <string>
#include <cstring> // memcpy

/**
 * @brief The CSVReader class reads simple CSV files
 *
 * CSV is a delimited data format that has fields/columns separated by the comma
 * character and records/rows terminated by newlines. "CSV" formats vary greatly
 * in choice of separator character. In particular, in locales where the comma
 * is used as a decimal separator, semicolon, TAB, or other characters are used
 * instead. [Reference: https://en.wikipedia.org/wiki/Comma-separated_values].
 *
 * To use, first create a CSVReader object and call addType() to add the type of a
 * column. Then call readFile().
 *
 * Once the file is in memory it can be read as columns of floats using
 * getColumn(). Or the whole CSV data can be copied to memory by defining
 * a struct that will hold the values from each row from the csv file and calling
 * copyToStruct() to create a vector with the data from the CSV file.
 *
 * This reader is currently very naive (but efficient) and might choke with
 * complex or malformed CSV files.
 *
 * \code
typedef struct {
	char s[32];
	double val1, val2, val3;
	bool b;
} RowTypes;

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

	CSVReader reader;
	reader.addType(CSVReader::STRING);
	reader.addType(CSVReader::REAL);
	reader.addType(CSVReader::REAL);
	reader.addType(CSVReader::REAL);
	reader.addType(CSVReader::BOOLEAN);
	reader.readFile("examples/csv/I13893-gm-21DIV-0001.csv");

	std::vector<RowTypes> rows = reader.copyToStruct<RowTypes>();
	for(auto row: rows) {
		std::cout << std::string(row.s) << " : "
		          << row.val1 << "   "
		          << row.val2 << "   "
		          << row.val3 << "   "
		          << (row.b ? "+" : "-")
		          << std::endl;
	}

	std::vector<double> column1 = reader.getColumn(1);
	for(auto value: column1) {
		std::cout << value << std::endl;
	}
	std::cout << " Num rows:" << rows.size() << std::endl;
	return 0;
	\endcode
 */
class CSVReader {
public:
	typedef enum {
		STRING,
		REAL,
		INTEGER,
		BOOLEAN,
		NONE
	} DataType;

	CSVReader(){}

	~CSVReader();

	/**
	 * @brief readFile reads the CSV file into internal memory
	 * @param fileName the csv file name
	 * \returns whether the file was successfully read.
	 *
	 * If the column data types have not been defined before calling this
	 * function using addType, then the reader will do its best job to derive
	 * the types.
	 */
	bool readFile(std::string fileName);

	/**
	 * @brief Set the delimiter used by readFile for parsing values
	 */
	CSVReader& delim(char v){ mDelim=v; return *this; }

	/**
	 * @brief addType
	 * @param type
	 */
	void addType(DataType type) {
		mDataTypes.push_back(type);
	}

	/**
	 * @brief Returns all columns from the csv file
	 * @param index column index
	 * @return vector with the data
	 */
	template<class DataStruct>
	std::vector<DataStruct> copyToStruct() const {
		std::vector<DataStruct> output;
		if (sizeof(DataStruct) < calculateRowLength()) {
			return output;
		}
		for (auto row: mData) {
			DataStruct newValues;
			memcpy(&newValues, row, sizeof(newValues));
			output.push_back(newValues);
		}

		return output;
	}

	/**
	 * @brief Returns a column from the csv file
	 * @param index column index
	 * @return vector with the data
	 *
	 * Values will be implicitly casted from their stored DataType to T.
	 */
	template <class T>
	std::vector<T> getColumn(int index) const {
		std::vector<T> out;
		auto offset = columnByteOffset(index);
		auto type = mDataTypes[index];
		for (auto row: mData) {
			switch(type){
			case REAL:
				out.push_back(*(const double *)(row + offset));
				break;
			case INTEGER:
				out.push_back(*(const int32_t *)(row + offset));
				break;
			case BOOLEAN:
				out.push_back(*(const bool *)(row + offset));
				break;
			// TODO: STRING -> std::string
			default:;
			}
		}
		return out;
	}

	std::vector<double> getColumn(int index) const {
		return getColumn<double>(index);
	}

	/// Get column names
	const std::vector<std::string>& columnNames() const { return mColumnNames; }

private:

	size_t columnByteOffset(int col) const;
	size_t calculateRowLength() const;
	size_t typeSize(CSVReader::DataType type) const;

	const size_t maxStringSize = 32;

	std::vector<std::string> mColumnNames;
	std::vector<DataType> mDataTypes;
	std::vector<char *> mData;
	char mDelim = ',';
};

#endif // INCLUDE_AL_CSVREADER_HPP
<commit_msg>CSVReader::getColumn specialize for std::string<commit_after>#ifndef INCLUDE_AL_CSVREADER_HPP
#define INCLUDE_AL_CSVREADER_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2012. The Regents of the University of California.
	All rights reserved.

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

		Redistributions of source code must retain the above copyright notice,
		this list of conditions and the following disclaimer.

		Redistributions in binary form must reproduce the above copyright
		notice, this list of conditions and the following disclaimer in the
		documentation and/or other materials provided with the distribution.

		Neither the name of the University of California nor the names of its
		contributors may be used to endorse or promote products derived from
		this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.

	File description:
	CSV File reader

	File author(s):
	Andres Cabrera mantaraya36@gmail.com 2017
*/

#include <vector>
#include <string>
#include <cstring> // memcpy

/**
 * @brief The CSVReader class reads simple CSV files
 *
 * CSV is a delimited data format that has fields/columns separated by the comma
 * character and records/rows terminated by newlines. "CSV" formats vary greatly
 * in choice of separator character. In particular, in locales where the comma
 * is used as a decimal separator, semicolon, TAB, or other characters are used
 * instead. [Reference: https://en.wikipedia.org/wiki/Comma-separated_values].
 *
 * To use, first create a CSVReader object and call addType() to add the type of a
 * column. Then call readFile().
 *
 * Once the file is in memory it can be read as columns of floats using
 * getColumn(). Or the whole CSV data can be copied to memory by defining
 * a struct that will hold the values from each row from the csv file and calling
 * copyToStruct() to create a vector with the data from the CSV file.
 *
 * This reader is currently very naive (but efficient) and might choke with
 * complex or malformed CSV files.
 *
 * \code
typedef struct {
	char s[32];
	double val1, val2, val3;
	bool b;
} RowTypes;

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

	CSVReader reader;
	reader.addType(CSVReader::STRING);
	reader.addType(CSVReader::REAL);
	reader.addType(CSVReader::REAL);
	reader.addType(CSVReader::REAL);
	reader.addType(CSVReader::BOOLEAN);
	reader.readFile("examples/csv/I13893-gm-21DIV-0001.csv");

	std::vector<RowTypes> rows = reader.copyToStruct<RowTypes>();
	for(auto row: rows) {
		std::cout << std::string(row.s) << " : "
		          << row.val1 << "   "
		          << row.val2 << "   "
		          << row.val3 << "   "
		          << (row.b ? "+" : "-")
		          << std::endl;
	}

	std::vector<double> column1 = reader.getColumn(1);
	for(auto value: column1) {
		std::cout << value << std::endl;
	}
	std::cout << " Num rows:" << rows.size() << std::endl;
	return 0;
	\endcode
 */
class CSVReader {
public:
	typedef enum {
		STRING,
		REAL,
		INTEGER,
		BOOLEAN,
		NONE
	} DataType;

	CSVReader(){}

	~CSVReader();

	/**
	 * @brief readFile reads the CSV file into internal memory
	 * @param fileName the csv file name
	 * \returns whether the file was successfully read.
	 *
	 * If the column data types have not been defined before calling this
	 * function using addType, then the reader will do its best job to derive
	 * the types.
	 */
	bool readFile(std::string fileName);

	/**
	 * @brief Set the delimiter used by readFile for parsing values
	 */
	CSVReader& delim(char v){ mDelim=v; return *this; }

	/**
	 * @brief addType
	 * @param type
	 */
	void addType(DataType type) {
		mDataTypes.push_back(type);
	}

	/**
	 * @brief Returns all columns from the csv file
	 * @param index column index
	 * @return vector with the data
	 */
	template<class DataStruct>
	std::vector<DataStruct> copyToStruct() const {
		std::vector<DataStruct> output;
		if (sizeof(DataStruct) < calculateRowLength()) {
			return output;
		}
		for (auto row: mData) {
			DataStruct newValues;
			memcpy(&newValues, row, sizeof(newValues));
			output.push_back(newValues);
		}

		return output;
	}

	/**
	 * @brief Returns a column from the csv file
	 * @param index column index
	 * @return vector with the data
	 *
	 * Values will be implicitly casted from their stored DataType to T.
	 */
	template <class T>
	std::vector<T> getColumn(int index) const;

	std::vector<double> getColumn(int index) const {
		return getColumn<double>(index);
	}

	/// Get column names
	const std::vector<std::string>& columnNames() const { return mColumnNames; }

private:

	size_t columnByteOffset(int col) const;
	size_t calculateRowLength() const;
	size_t typeSize(CSVReader::DataType type) const;

	const size_t maxStringSize = 32;

	std::vector<std::string> mColumnNames;
	std::vector<DataType> mDataTypes;
	std::vector<char *> mData;
	char mDelim = ',';
};

template <class T>
std::vector<T> CSVReader::getColumn(int index) const {
	std::vector<T> out;
	auto offset = columnByteOffset(index);
	auto type = mDataTypes[index];
	for (auto row: mData) {
		switch(type){
		case REAL:
			out.push_back(*(const double *)(row + offset));
			break;
		case INTEGER:
			out.push_back(*(const int32_t *)(row + offset));
			break;
		case BOOLEAN:
			out.push_back(*(const bool *)(row + offset));
			break;
		default:;
		}
	}
	return out;
}

template <>
inline std::vector<std::string> CSVReader::getColumn<std::string>(int index) const {
	std::vector<std::string> out;
	auto offset = columnByteOffset(index);
	auto type = mDataTypes[index];
	for (auto row: mData) {
		switch(type){
		case STRING:
			out.emplace_back((const char *)(row + offset));
			break;
		default:;
		}
	}
	return out;
}

#endif // INCLUDE_AL_CSVREADER_HPP
<|endoftext|>


<commit_before>#ifndef INCLUDE_AL_BUFFER_HPP
#define INCLUDE_AL_BUFFER_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2012. The Regents of the University of California.
	All rights reserved.

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

		Redistributions of source code must retain the above copyright notice,
		this list of conditions and the following disclaimer.

		Redistributions in binary form must reproduce the above copyright
		notice, this list of conditions and the following disclaimer in the
		documentation and/or other materials provided with the distribution.

		Neither the name of the University of California nor the names of its
		contributors may be used to endorse or promote products derived from
		this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.

	File description:
	Variably sized one-dimensional array

	File author(s):
	Lance Putnam, 2010, putnam.lance@gmail.com
*/

#include <algorithm>
#include <vector>

namespace al{

/// Buffer

/// This buffer automatically expands itself as new elements are added.
/// Additionally, its logical size can be reduced without triggering memory
/// deallocations.
template <class T, class Alloc=std::allocator<T> >
class Buffer : protected Alloc{
	typedef Alloc super;
public:

	/// @param[in] size			Initial size
	explicit Buffer(int size=0)
	:	mElems(size), mSize(size)
	{}

	/// @param[in] size			Initial size
	/// @param[in] capacity		Initial capacity
	Buffer(int size, int capacity)
	:	mElems(capacity), mSize(size)
	{}

	~Buffer(){}

	int capacity() const { return mElems.size(); }		///< Returns total capacity
	int size() const { return mSize; }					///< Returns size
	const T * elems() const { return &mElems[0]; }		///< Returns C pointer to elements
	T * elems(){ return &mElems[0]; }					///< Returns C pointer to elements

	/// Get element at index
	T& operator[](int i){ return mElems[i]; }

	/// Get element at index (read-only)
	const T& operator[](int i) const { return mElems[i]; }

	/// Assign value to elements

	/// This function fills a Buffer with n copies of the given value. Note that
	/// the assignment completely changes the buffer and that the resulting size
	/// is the same as the number of elements assigned. Old data may be lost.
	void assign(int n, const T& v){ mElems.assign(n,v); }

	/// Get last element
	T& last(){ return mElems[size()-1]; }
	const T& last() const { return mElems[size()-1]; }

	/// Resets size to zero without deallocating allocated memory
	void reset(){ mSize=0; }

	/// Resize buffer

	/// This will set both the size and capacity of the buffer to the requested
	/// size. If the number is smaller than the current size the buffer is
	/// truncated, otherwise the buffer is extended and new elements are
	/// default-constructed.
	void resize(int n){
		mElems.resize(n);
		setSize(n);
	}

	/// Set size of buffer

	/// If the requested size is larger than the current capacity, then the
	/// buffer will be resized.
	void size(int n){
		if(capacity() < n) resize(n);
		else setSize(n);
	}

	/// Appends element to end of buffer growing its size if necessary
	void append(const T& v, double growFactor=2){

		// Grow array if too small
		if(size() >= capacity()){
			// Copy argument since it may be an element in current memory range
			// which may become invalid after the resize.
			const T vsafecopy = v;
			mElems.resize((size() ? size() : 4)*growFactor);
			super::construct(elems()+size(), vsafecopy);
		}
		else{
			super::construct(elems()+size(), v);
		}
		++mSize;
	}
	/// synonym for append():
	void push_back(const T& v, double growFactor=2) { append(v, growFactor); }

	/// Append elements of another Buffer

	/// Note: not safe to apply this to itself
	///
	void append(const Buffer<T>& src){
		append(src.elems(), src.size());
	}

	/// Append elements of an array
	void append(const T * src, int len){
		int oldsize = size();
		size(size() + len);
		std::copy(src, src + len, mElems.begin() + oldsize);
	}

	/// Repeat last element
	void repeatLast(){ append(last()); }

	/// Insert new elements after each existing element

	/// @param[in] n	Expansion factor; new size is n times old size
	/// @param[in] dup	If true, new elements are duplicates of existing elements.
	///					If false, new elements are default constructed.
	template <int n, bool dup>
	void expand(){
		size(size()*n);
		const int Nd = dup ? n : 1;
		for(int i=size()/n-1; i>=0; --i){
			const T& v = (*this)[i];
			for(int j=0; j<Nd; ++j) Alloc::construct(elems()+n*i+j, v);
		}
	}

private:
	std::vector<T, Alloc> mElems;
	int mSize;		// logical size array

	void setSize(int n){ mSize=n; }
};

/// Ring buffer

/// This buffer allows potentially large amounts of data to be buffered without
/// moving memory. This is accomplished by use of a moving write tap.
template <class T, class Alloc=std::allocator<T> >
class RingBuffer : protected Alloc {
public:

	/// Default constructor; does not allocate memory
	RingBuffer(): mPos(-1), mFill(0){}

	/// @param[in] size		number of elements
	/// @param[in] v		value to initialize elements to
	explicit RingBuffer(unsigned size, const T& v=T())
	:	mPos(size), mFill(0)
	{
		resize(size,v);
	}

	/// Get number of elements
	int size() const { return mElems.size(); }

	/// Get absolute index of most recently written element
	int pos() const { return mPos; }

	/// Get fill amount of buffer
	int fill() const { return mFill; }

	/// Get element at absolute index
	T& operator[](int i){ return mElems[i]; }

	/// Get element at absolute index (read-only)
	const T& operator[](int i) const { return mElems[i]; }

	/// Write new element
	void write(const T& v){
		if(mFill < size()) ++mFill;
		++mPos; if(pos() == size()){ mPos=0; }
		Alloc::construct(&mElems[0] + pos(), v);
	}

	/// Get reference to element relative to newest element
	T& read(int i){ return mElems[wrapOnce(pos()-i, size())]; }

	/// Get reference to element relative to newest element (read-only)
	const T& read(int i) const { return readFrom(pos(), i); }

	/// Get reference to older element relative to some newer element (read-only)

	/// @param[in] from		absolute index the read is relative to
	/// @param[in] dist		distance into past relative to 'from' of the returned element
	const T& readFrom(int from, int dist) const {
		return mElems[wrapOnce(from-dist, size())];
	}

	/// \returns reference to newest element
	T& newest(){ return mElems[pos()]; }

	/// \returns reference to newest element (read-only)
	const T& newest() const { return mElems[pos()]; }

	/// Resize buffer

	/// @param[in] n	number of elements
	/// @param[in] v	initialization value of newly allocated elements
	void resize(int n, const T& v=T()){
		mElems.resize(n,v);
		if(mPos >=n) mPos = n-1;
	}

protected:
	std::vector<T, Alloc> mElems;
	int mPos;
	int mFill;

	// Moves value one period closer to interval [0, max)
	static int wrapOnce(int v, int max){
		if(v <  0)   return v+max;
		if(v >= max) return v-max;
		return v;
	}
};

/// Constant size shift buffer

/// This is a first-in, first-out buffer with a constant number of elements.
/// Adding new elements to the buffer physically moves existing elements. The
/// advantage of moving memory like this is that elements stay logically ordered
/// making access faster and operating on the history easier.
template <int N, class T>
class ShiftBuffer{
public:

	/// @param[in] v	Value to initialize all elements to
	ShiftBuffer(const T& v=T()){ assign(v); }

	/// Get number of elements
	static int size(){ return N; }

	/// Get pointer to elements (read-only)
	const T * elems() const { return &mElems[0]; }

	/// Get pointer to elements
	T * elems(){ return &mElems[0]; }

	/// Get reference to element at index
	T& operator[](int i){ return mElems[i];}

	/// Get reference to element at index (read-only)
	const T& operator[](int i) const { return mElems[i]; }

	/// Push new element onto buffer. Newest element is at index 0.
	void operator()(const T& v){
		for(int i=N-1; i>0; --i) mElems[i] = mElems[i-1];
		mElems[0]=v;
	}

	/// Set all elements to argument
	void assign(const T& v){ for(int i=0;i<N;++i) mElems[i]=v; }

	/// Zero bytes of all elements
	void zero(){ memset(mElems, 0, N * sizeof(T)); }

protected:
	T mElems[N];
};

} // al::

#endif
<commit_msg>RingBuffer: added next method<commit_after>#ifndef INCLUDE_AL_BUFFER_HPP
#define INCLUDE_AL_BUFFER_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2012. The Regents of the University of California.
	All rights reserved.

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

		Redistributions of source code must retain the above copyright notice,
		this list of conditions and the following disclaimer.

		Redistributions in binary form must reproduce the above copyright
		notice, this list of conditions and the following disclaimer in the
		documentation and/or other materials provided with the distribution.

		Neither the name of the University of California nor the names of its
		contributors may be used to endorse or promote products derived from
		this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.

	File description:
	Variably sized one-dimensional array

	File author(s):
	Lance Putnam, 2010, putnam.lance@gmail.com
*/

#include <algorithm>
#include <vector>

namespace al{

/// Buffer

/// This buffer automatically expands itself as new elements are added.
/// Additionally, its logical size can be reduced without triggering memory
/// deallocations.
template <class T, class Alloc=std::allocator<T> >
class Buffer : protected Alloc{
	typedef Alloc super;
public:

	/// @param[in] size			Initial size
	explicit Buffer(int size=0)
	:	mElems(size), mSize(size)
	{}

	/// @param[in] size			Initial size
	/// @param[in] capacity		Initial capacity
	Buffer(int size, int capacity)
	:	mElems(capacity), mSize(size)
	{}

	~Buffer(){}

	int capacity() const { return mElems.size(); }		///< Returns total capacity
	int size() const { return mSize; }					///< Returns size
	const T * elems() const { return &mElems[0]; }		///< Returns C pointer to elements
	T * elems(){ return &mElems[0]; }					///< Returns C pointer to elements

	/// Get element at index
	T& operator[](int i){ return mElems[i]; }

	/// Get element at index (read-only)
	const T& operator[](int i) const { return mElems[i]; }

	/// Assign value to elements

	/// This function fills a Buffer with n copies of the given value. Note that
	/// the assignment completely changes the buffer and that the resulting size
	/// is the same as the number of elements assigned. Old data may be lost.
	void assign(int n, const T& v){ mElems.assign(n,v); }

	/// Get last element
	T& last(){ return mElems[size()-1]; }
	const T& last() const { return mElems[size()-1]; }

	/// Resets size to zero without deallocating allocated memory
	void reset(){ mSize=0; }

	/// Resize buffer

	/// This will set both the size and capacity of the buffer to the requested
	/// size. If the number is smaller than the current size the buffer is
	/// truncated, otherwise the buffer is extended and new elements are
	/// default-constructed.
	void resize(int n){
		mElems.resize(n);
		setSize(n);
	}

	/// Set size of buffer

	/// If the requested size is larger than the current capacity, then the
	/// buffer will be resized.
	void size(int n){
		if(capacity() < n) resize(n);
		else setSize(n);
	}

	/// Appends element to end of buffer growing its size if necessary
	void append(const T& v, double growFactor=2){

		// Grow array if too small
		if(size() >= capacity()){
			// Copy argument since it may be an element in current memory range
			// which may become invalid after the resize.
			const T vsafecopy = v;
			mElems.resize((size() ? size() : 4)*growFactor);
			super::construct(elems()+size(), vsafecopy);
		}
		else{
			super::construct(elems()+size(), v);
		}
		++mSize;
	}
	/// synonym for append():
	void push_back(const T& v, double growFactor=2) { append(v, growFactor); }

	/// Append elements of another Buffer

	/// Note: not safe to apply this to itself
	///
	void append(const Buffer<T>& src){
		append(src.elems(), src.size());
	}

	/// Append elements of an array
	void append(const T * src, int len){
		int oldsize = size();
		size(size() + len);
		std::copy(src, src + len, mElems.begin() + oldsize);
	}

	/// Repeat last element
	void repeatLast(){ append(last()); }

	/// Insert new elements after each existing element

	/// @param[in] n	Expansion factor; new size is n times old size
	/// @param[in] dup	If true, new elements are duplicates of existing elements.
	///					If false, new elements are default constructed.
	template <int n, bool dup>
	void expand(){
		size(size()*n);
		const int Nd = dup ? n : 1;
		for(int i=size()/n-1; i>=0; --i){
			const T& v = (*this)[i];
			for(int j=0; j<Nd; ++j) Alloc::construct(elems()+n*i+j, v);
		}
	}

private:
	std::vector<T, Alloc> mElems;
	int mSize;		// logical size array

	void setSize(int n){ mSize=n; }
};

/// Ring buffer

/// This buffer allows potentially large amounts of data to be buffered without
/// moving memory. This is accomplished by use of a moving write tap.
template <class T, class Alloc=std::allocator<T> >
class RingBuffer : protected Alloc {
public:

	/// Default constructor; does not allocate memory
	RingBuffer(): mPos(-1), mFill(0){}

	/// @param[in] size		number of elements
	/// @param[in] v		value to initialize elements to
	explicit RingBuffer(unsigned size, const T& v=T())
	:	mPos(size), mFill(0)
	{
		resize(size,v);
	}

	/// Get number of elements
	int size() const { return mElems.size(); }

	/// Get absolute index of most recently written element
	int pos() const { return mPos; }

	/// Get fill amount of buffer
	int fill() const { return mFill; }

	/// Get element at absolute index
	T& operator[](int i){ return mElems[i]; }

	/// Get element at absolute index (read-only)
	const T& operator[](int i) const { return mElems[i]; }

	/// Obtain next element in buffer

	/// This method returns a reference to the next available element in the
	/// buffer. This is an alternative to calling write() that does not require
	/// constructing a new object, but instead returns the oldest element in
	/// the buffer. The returned reference should be assumed to be in an unknown
	/// state, thus should be initialized properly.
	T& next(){
		if(mFill < size()) ++mFill;
		++mPos; if(pos() == size()){ mPos=0; }
		return mElems[pos()];
	}

	/// Write new element
	void write(const T& v){
		Alloc::construct(&next(), v);
	}

	/// Get reference to element relative to newest element
	T& read(int i){ return mElems[wrapOnce(pos()-i, size())]; }

	/// Get reference to element relative to newest element (read-only)
	const T& read(int i) const { return readFrom(pos(), i); }

	/// Get reference to older element relative to some newer element (read-only)

	/// @param[in] from		absolute index the read is relative to
	/// @param[in] dist		distance into past relative to 'from' of the returned element
	const T& readFrom(int from, int dist) const {
		return mElems[wrapOnce(from-dist, size())];
	}

	/// \returns reference to newest element
	T& newest(){ return mElems[pos()]; }

	/// \returns reference to newest element (read-only)
	const T& newest() const { return mElems[pos()]; }

	/// Resize buffer

	/// @param[in] n	number of elements
	/// @param[in] v	initialization value of newly allocated elements
	void resize(int n, const T& v=T()){
		mElems.resize(n,v);
		if(mPos >=n) mPos = n-1;
	}

protected:
	std::vector<T, Alloc> mElems;
	int mPos;
	int mFill;

	// Moves value one period closer to interval [0, max)
	static int wrapOnce(int v, int max){
		if(v <  0)   return v+max;
		if(v >= max) return v-max;
		return v;
	}
};

/// Constant size shift buffer

/// This is a first-in, first-out buffer with a constant number of elements.
/// Adding new elements to the buffer physically moves existing elements. The
/// advantage of moving memory like this is that elements stay logically ordered
/// making access faster and operating on the history easier.
template <int N, class T>
class ShiftBuffer{
public:

	/// @param[in] v	Value to initialize all elements to
	ShiftBuffer(const T& v=T()){ assign(v); }

	/// Get number of elements
	static int size(){ return N; }

	/// Get pointer to elements (read-only)
	const T * elems() const { return &mElems[0]; }

	/// Get pointer to elements
	T * elems(){ return &mElems[0]; }

	/// Get reference to element at index
	T& operator[](int i){ return mElems[i];}

	/// Get reference to element at index (read-only)
	const T& operator[](int i) const { return mElems[i]; }

	/// Push new element onto buffer. Newest element is at index 0.
	void operator()(const T& v){
		for(int i=N-1; i>0; --i) mElems[i] = mElems[i-1];
		mElems[0]=v;
	}

	/// Set all elements to argument
	void assign(const T& v){ for(int i=0;i<N;++i) mElems[i]=v; }

	/// Zero bytes of all elements
	void zero(){ memset(mElems, 0, N * sizeof(T)); }

protected:
	T mElems[N];
};

} // al::

#endif
<|endoftext|>


<commit_before>#include "explorer.h"

Explorer::Explorer(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    QString sPath = "F:/";
    dirmodel = new QFileSystemModel(this);
    dirmodel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs);
    dirmodel->setRootPath(sPath);

    ui->treeView->setModel(dirmodel);

    filemodel = new QFileSystemModel(this);
    filemodel->setFilter(QDir::NoDotAndDotDot | QDir::Files);
    filemodel->setRootPath(sPath);

    ui->listView->setModel(filemodel);

}

Explorer::~Explorer()
{
    delete ui;
}

void Explorer::on_treeView_clicked(QModelIndex index)
{
    QString sPath = dirmodel->fileInfo(index).absoluteFilePath();
    ui->listView->setRootIndex(filemodel->setRootPath(sPath));
}
<commit_msg>Delete explorer.cpp<commit_after><|endoftext|>


<commit_before>#ifndef MDL_PARAGRAPH_HPP
#define MDL_PARAGRAPH_HPP

#include "line_element.hpp"

#include <vector>

/**
 * @brief Base class for paragraphs
 *
 * Every paragraph is meant to be followed by a newline.
 **/
class Paragraph {
	protected:
		/** @brief Indicate if the paragraph is the last of its type **/
		bool _last;
		/** @brief List of LineElement in this Paragraph **/
		std::vector<LineElement*> _elements;
	public:
		/**
		 * @brief Constructor
		 **/
		Paragraph();

		/**
		 * @brief Conversion constructor
		 *
		 * @param p Pointer to the original paragraph
		 **/
		Paragraph(Paragraph * p);

		/**
		 * @brief Destructor
		 **/
		~Paragraph();

		/**
		 * @brief Append a line element
		 *
		 * @param e The pointer to the LineElement to append
		 **/
		virtual void append_line_element(LineElement * e);

		/**
		 * @brief Get the number of LineElement
		 **/
		size_t size(void) const;

		/**
		 * @brief Access a line element
		 *
		 * @param index The index of the requested LineElement
		 * @return A pointer to the LineElement, nullptr
		 * if the index does not exist.
		 **/
		LineElement * element(size_t index = 0) const;

		/**
		 * @brief Access a line element
		 *
		 * @param index The index of the requested LineElement
		 * @return A pointer to the LineElement, nullptr
		 * if the index does not exist.
		 **/
		LineElement * operator[] (size_t index) const;

		/**
		 * @brief Level of the paragraph
		 *
		 * This value is returned by Paragraph::level()
		 **/
		enum class Level {
			Text /** This is the default level **/,
			Title1 /** First title **/,
			Title2 /** Second title **/,
			Title3 /** Third title **/,
			Title4 /** Fourth title **/,
			Title5 /** Fifth title **/,
			Title6 /** Sixth title **/,
			UList1 /** Unordered list **/,
			OList1 /** Ordered list **/,
			Quote /** Quote paragraph **/,
			Code /** Code paragraph **/
		};

		/**
		 * @brief Get the Paragraph's Paragraph::Level
		 *
		 * @return The level of the Paragraph
		 **/
		virtual Level level(void) const = 0;

		/**
		 * @brief Setter for _last
		 **/
		void last(const bool & last);

		/**
		 * @brief Getter for _last
		 **/
		bool last(void) const;
};

#endif // MDL_PARAGRAPH_HPP
<commit_msg>Reorder Paragraph::Level<commit_after>#ifndef MDL_PARAGRAPH_HPP
#define MDL_PARAGRAPH_HPP

#include "line_element.hpp"

#include <vector>

/**
 * @brief Base class for paragraphs
 *
 * Every paragraph is meant to be followed by a newline.
 **/
class Paragraph {
	protected:
		/** @brief Indicate if the paragraph is the last of its type **/
		bool _last;
		/** @brief List of LineElement in this Paragraph **/
		std::vector<LineElement*> _elements;
	public:
		/**
		 * @brief Constructor
		 **/
		Paragraph();

		/**
		 * @brief Conversion constructor
		 *
		 * @param p Pointer to the original paragraph
		 **/
		Paragraph(Paragraph * p);

		/**
		 * @brief Destructor
		 **/
		~Paragraph();

		/**
		 * @brief Append a line element
		 *
		 * @param e The pointer to the LineElement to append
		 **/
		virtual void append_line_element(LineElement * e);

		/**
		 * @brief Get the number of LineElement
		 **/
		size_t size(void) const;

		/**
		 * @brief Access a line element
		 *
		 * @param index The index of the requested LineElement
		 * @return A pointer to the LineElement, nullptr
		 * if the index does not exist.
		 **/
		LineElement * element(size_t index = 0) const;

		/**
		 * @brief Access a line element
		 *
		 * @param index The index of the requested LineElement
		 * @return A pointer to the LineElement, nullptr
		 * if the index does not exist.
		 **/
		LineElement * operator[] (size_t index) const;

		/**
		 * @brief Level of the paragraph
		 *
		 * This value is returned by Paragraph::level()
		 **/
		enum class Level {
			Text /** This is the default level **/,
			Title1 /** First title **/,
			Title2 /** Second title **/,
			Title3 /** Third title **/,
			Title4 /** Fourth title **/,
			Title5 /** Fifth title **/,
			Title6 /** Sixth title **/,
			OList1 /** Ordered list **/,
			UList1 /** Unordered list **/,
			Quote /** Quote paragraph **/,
			Code /** Code paragraph **/
		};

		/**
		 * @brief Get the Paragraph's Paragraph::Level
		 *
		 * @return The level of the Paragraph
		 **/
		virtual Level level(void) const = 0;

		/**
		 * @brief Setter for _last
		 **/
		void last(const bool & last);

		/**
		 * @brief Getter for _last
		 **/
		bool last(void) const;
};

#endif // MDL_PARAGRAPH_HPP
<|endoftext|>


<commit_before>/**
 * This file is part of the "libstx" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * libstx is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <string.h>
#include "stx/bufferutil.h"
#include "stx/exception.h"
#include "stx/inspect.h"
#include "stx/http/httpparser.h"

namespace stx {
namespace http {

const char HTTPParser::kContentLengthHeader[] = "Content-Length";
const char HTTPParser::kConnectionHeader[] = "Connection";

HTTPParser::HTTPParser(
    kParserMode mode,
    size_t buffer_size /* = kDefaultBufferSize */) :
    on_method_cb_(nullptr),
    on_uri_cb_(nullptr),
    on_version_cb_(nullptr),
    on_status_code_cb_(nullptr),
    on_status_name_cb_(nullptr),
    on_header_cb_(nullptr),
    on_headers_complete_cb_(nullptr),
    on_body_chunk_cb_(nullptr),
    mode_(mode),
    body_bytes_read_(0),
    body_bytes_expected_(0),
    expect_body_(true) {
  switch (mode) {
    case PARSE_HTTP_REQUEST:
      state_ = S_REQ_METHOD;
      break;

    case PARSE_HTTP_RESPONSE:
      state_ = S_RES_VERSION;
      break;
  }

  buf_.reserve(buffer_size);
}

HTTPParser::kParserState HTTPParser::state() const {
  return state_;
}

void HTTPParser::onMethod(
    std::function<void(HTTPMessage::kHTTPMethod)> callback) {
  on_method_cb_ = callback;
}

void HTTPParser::onURI(
    std::function<void(const char* data, size_t size)> callback) {
  on_uri_cb_ = callback;
}

void HTTPParser::onVersion(
    std::function<void(const char* data, size_t size)> callback) {
  on_version_cb_ = callback;
}

void HTTPParser::onStatusCode(std::function<void(int)> callback) {
  on_status_code_cb_ = callback;
}

void HTTPParser::onStatusName(
    std::function<void(const char* data, size_t size)> callback) {
  on_status_name_cb_ = callback;
}

void HTTPParser::onHeader(std::function<void(
    const char* key,
    size_t key_len,
    const char* val,
    size_t val_len)> callback) {
  on_header_cb_ = callback;
}

void HTTPParser::onHeadersComplete(std::function<void()> callback) {
  on_headers_complete_cb_ = callback;
}

void HTTPParser::onBodyChunk(
    std::function<void(const char* data, size_t size)> callback) {
  on_body_chunk_cb_ = callback;
}

void HTTPParser::parse(const char* data, size_t size) {
  const char* begin = data;
  const char* end = data + size;

  while (begin < end) {
    switch (state_) {
      case S_REQ_METHOD:
        parseMethod(&begin, end);
        break;
      case S_REQ_URI:
        parseURI(&begin, end);
        break;
      case S_REQ_VERSION:
        parseRequestVersion(&begin, end);
        break;
      case S_RES_VERSION:
        parseResponseVersion(&begin, end);
        break;
      case S_RES_STATUS_CODE:
        parseResponseStatusCode(&begin, end);
        break;
      case S_RES_STATUS_NAME:
        parseResponseStatusName(&begin, end);
        break;
      case S_HEADER:
        parseHeader(&begin, end);
        break;
      case S_DONE:
        if (mode_ == PARSE_HTTP_REQUEST) {
          RAISE(kParseError, "invalid trailing bytes");
        }
        /* fallthrough */
      case S_BODY:
        readBody(&begin, end);
        break;

    }
  }
}

void HTTPParser::eof() {
  switch (state_) {
    case S_REQ_METHOD:
    case S_REQ_URI:
    case S_REQ_VERSION:
    case S_RES_VERSION:
    case S_RES_STATUS_CODE:
    case S_RES_STATUS_NAME:
    case S_HEADER:
    case S_BODY:
      if (body_bytes_expected_ != -1 &&
          body_bytes_read_ < body_bytes_expected_) {
        RAISE(kParseError, "unexpected end of file");
      } else {
        state_ = S_DONE;
      }
      return;
    case S_DONE:
      return;
  }
}

void HTTPParser::parseMethod(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    state_ = S_REQ_URI;
    (*begin)++;

    if (on_method_cb_) {
      if (buf_ == "CONNECT") {
        on_method_cb_(HTTPMessage::M_CONNECT);
        buf_.clear();
        return;
      }

      if (buf_ == "DELETE") {
        on_method_cb_(HTTPMessage::M_DELETE);
        buf_.clear();
        return;
      }

      if (buf_ == "GET") {
        on_method_cb_(HTTPMessage::M_GET);
        buf_.clear();
        return;
      }

      if (buf_ == "HEAD") {
        on_method_cb_(HTTPMessage::M_HEAD);
        buf_.clear();
        return;
      }

      if (buf_ == "OPTIONS") {
        on_method_cb_(HTTPMessage::M_OPTIONS);
        buf_.clear();
        return;
      }

      if (buf_ == "POST") {
        on_method_cb_(HTTPMessage::M_POST);
        buf_.clear();
        return;
      }

      if (buf_ == "PUT") {
        on_method_cb_(HTTPMessage::M_PUT);
        buf_.clear();
        return;
      }

      if (buf_ == "TRACE"){
        on_method_cb_(HTTPMessage::M_TRACE);
        buf_.clear();
        return;
      }

      RAISEF(kParseError, "Invalid HTTP method: $0", buf_.toString());
    }
  }

  if (buf_.size() > kMaxMethodSize) {
    RAISEF(kParseError, "HTTP method too large, max is $0", kMaxMethodSize);
  }
}

void HTTPParser::parseURI(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    if (on_uri_cb_) {
      on_uri_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_REQ_VERSION;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxURISize) {
    RAISEF(kParseError, "HTTP URI too large, max is $0", kMaxURISize);
  }
}

void HTTPParser::parseRequestVersion(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (on_version_cb_) {
      on_version_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_HEADER;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseResponseVersion(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    if (strncasecmp((char *) buf_.data(), "HTTP/1.0", buf_.size()) == 0) {
      body_bytes_expected_ = -1;
    }

    if (on_version_cb_) {
      on_version_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_RES_STATUS_CODE;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseResponseStatusCode(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    std::string status_code_str((char *) buf_.data(), buf_.size());
    int status_code = 1;

    try {
      status_code = std::stoi(status_code_str);
    } catch (const std::exception& e) {
      RAISEF(kParseError, "invalid http status code: $0", status_code_str);
    }

    if (on_status_code_cb_) {
      on_status_code_cb_(status_code);
    }

    buf_.clear();
    state_ = S_RES_STATUS_NAME;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxURISize) {
    RAISEF(kParseError, "HTTP URI too large, max is $0", kMaxURISize);
  }
}

void HTTPParser::parseResponseStatusName(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (on_status_name_cb_) {
      on_status_name_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_HEADER;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseHeader(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (buf_.size() > 0) {
      auto hkey = (char*) buf_.data();
      auto hkey_len = buf_.find(':');
      if (hkey_len == Buffer::npos) {
        RAISEF(kParseError, "invalid HTTP header line: $0", buf_.toString());
      }

      auto hval = hkey + hkey_len + 1;
      auto hval_len = buf_.size() - hkey_len - 1;
      while (hval_len > 0 && *hval == ' ') {
        hval++;
        hval_len--;
      }

      processHeader(hkey, hkey_len, hval, hval_len);
      buf_.clear();
      state_ = S_HEADER;
    } else {
      if (body_bytes_expected_ == 0) {
        state_ = S_DONE;
      } else {
        state_ = S_BODY;
      }

      if (on_headers_complete_cb_) {
        on_headers_complete_cb_();
      }
    }

    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxHeaderSize) {
    RAISEF(kParseError, "HTTP header too large, max is $0", kMaxHeaderSize);
  }
}

void HTTPParser::processHeader(
    const char* key,
    size_t key_len,
    const char* val,
    size_t val_len) {
  if (expect_body_ &&
      key_len == strlen(kContentLengthHeader) &&
      strncasecmp(key, kContentLengthHeader, key_len) == 0) {
    std::string content_length_str(val, val_len);
    try {
      body_bytes_expected_ = std::stoul(content_length_str);
    } catch (const std::exception& e) {
      RAISEF(kParseError, "invalid content length: $0", content_length_str);
    }
  }

  if (expect_body_ &&
      key_len == strlen(kConnectionHeader) &&
      strncasecmp(key, kConnectionHeader, key_len) == 0 &&
      val_len == strlen("Close") &&
      strncasecmp(val, "Close", val_len) == 0) {
    body_bytes_expected_ = -1;
  }

  if (on_header_cb_) {
    on_header_cb_(key, key_len, val, val_len);
  }
}

void HTTPParser::readBody(const char** begin, const char* end) {
  body_bytes_read_ += end - *begin;

  if (body_bytes_read_ == body_bytes_expected_) {
    state_ = HTTPParser::S_DONE;
  }

  //if ((body_bytes_read_ > body_bytes_expected_) &&
  //    !(body_bytes_expected_ == 0 && mode_ == PARSE_HTTP_RESPONSE)) {
  //  RAISE(kParseError, "invalid trailing body bytes");
  //}

  if (on_body_chunk_cb_) {
    on_body_chunk_cb_(*begin, end - *begin);
  }

  *begin = end;
}

bool HTTPParser::readUntil(const char** begin, const char* end, char search) {
  auto cur = *begin;
  for (; cur < end && *cur != search; ++cur);
  buf_.append(*begin, (cur - *begin));
  *begin = cur;
  return cur != end && *cur == search;
}

void HTTPParser::reset() {
  switch (mode_) {
    case PARSE_HTTP_REQUEST:
      state_ = S_REQ_METHOD;
      break;

    case PARSE_HTTP_RESPONSE:
      state_ = S_RES_VERSION;
      break;
  }

  buf_.clear();
  body_bytes_read_ = 0;
  body_bytes_expected_ = 0;
  expect_body_ = true;
}

void HTTPParser::ignoreBody() {
  expect_body_ = false;
}

}
}
<commit_msg>allow http message bodies without content-length only for responses<commit_after>/**
 * This file is part of the "libstx" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * libstx is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <string.h>
#include "stx/bufferutil.h"
#include "stx/exception.h"
#include "stx/inspect.h"
#include "stx/http/httpparser.h"

namespace stx {
namespace http {

const char HTTPParser::kContentLengthHeader[] = "Content-Length";
const char HTTPParser::kConnectionHeader[] = "Connection";

HTTPParser::HTTPParser(
    kParserMode mode,
    size_t buffer_size /* = kDefaultBufferSize */) :
    on_method_cb_(nullptr),
    on_uri_cb_(nullptr),
    on_version_cb_(nullptr),
    on_status_code_cb_(nullptr),
    on_status_name_cb_(nullptr),
    on_header_cb_(nullptr),
    on_headers_complete_cb_(nullptr),
    on_body_chunk_cb_(nullptr),
    mode_(mode),
    body_bytes_read_(0),
    body_bytes_expected_(0),
    expect_body_(true) {
  switch (mode) {
    case PARSE_HTTP_REQUEST:
      state_ = S_REQ_METHOD;
      break;

    case PARSE_HTTP_RESPONSE:
      state_ = S_RES_VERSION;
      break;
  }

  buf_.reserve(buffer_size);
}

HTTPParser::kParserState HTTPParser::state() const {
  return state_;
}

void HTTPParser::onMethod(
    std::function<void(HTTPMessage::kHTTPMethod)> callback) {
  on_method_cb_ = callback;
}

void HTTPParser::onURI(
    std::function<void(const char* data, size_t size)> callback) {
  on_uri_cb_ = callback;
}

void HTTPParser::onVersion(
    std::function<void(const char* data, size_t size)> callback) {
  on_version_cb_ = callback;
}

void HTTPParser::onStatusCode(std::function<void(int)> callback) {
  on_status_code_cb_ = callback;
}

void HTTPParser::onStatusName(
    std::function<void(const char* data, size_t size)> callback) {
  on_status_name_cb_ = callback;
}

void HTTPParser::onHeader(std::function<void(
    const char* key,
    size_t key_len,
    const char* val,
    size_t val_len)> callback) {
  on_header_cb_ = callback;
}

void HTTPParser::onHeadersComplete(std::function<void()> callback) {
  on_headers_complete_cb_ = callback;
}

void HTTPParser::onBodyChunk(
    std::function<void(const char* data, size_t size)> callback) {
  on_body_chunk_cb_ = callback;
}

void HTTPParser::parse(const char* data, size_t size) {
  const char* begin = data;
  const char* end = data + size;

  while (begin < end) {
    switch (state_) {
      case S_REQ_METHOD:
        parseMethod(&begin, end);
        break;
      case S_REQ_URI:
        parseURI(&begin, end);
        break;
      case S_REQ_VERSION:
        parseRequestVersion(&begin, end);
        break;
      case S_RES_VERSION:
        parseResponseVersion(&begin, end);
        break;
      case S_RES_STATUS_CODE:
        parseResponseStatusCode(&begin, end);
        break;
      case S_RES_STATUS_NAME:
        parseResponseStatusName(&begin, end);
        break;
      case S_HEADER:
        parseHeader(&begin, end);
        break;
      case S_DONE:
        if (mode_ == PARSE_HTTP_REQUEST) {
          RAISE(kParseError, "invalid trailing bytes");
        }
        /* fallthrough */
      case S_BODY:
        readBody(&begin, end);
        break;

    }
  }
}

void HTTPParser::eof() {
  switch (state_) {
    case S_REQ_METHOD:
    case S_REQ_URI:
    case S_REQ_VERSION:
    case S_RES_VERSION:
    case S_RES_STATUS_CODE:
    case S_RES_STATUS_NAME:
    case S_HEADER:
    case S_BODY:
      if (body_bytes_expected_ != -1 &&
          body_bytes_read_ < body_bytes_expected_) {
        RAISE(kParseError, "unexpected end of file");
      } else {
        state_ = S_DONE;
      }
      return;
    case S_DONE:
      return;
  }
}

void HTTPParser::parseMethod(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    state_ = S_REQ_URI;
    (*begin)++;

    if (on_method_cb_) {
      if (buf_ == "CONNECT") {
        on_method_cb_(HTTPMessage::M_CONNECT);
        buf_.clear();
        return;
      }

      if (buf_ == "DELETE") {
        on_method_cb_(HTTPMessage::M_DELETE);
        buf_.clear();
        return;
      }

      if (buf_ == "GET") {
        on_method_cb_(HTTPMessage::M_GET);
        buf_.clear();
        return;
      }

      if (buf_ == "HEAD") {
        on_method_cb_(HTTPMessage::M_HEAD);
        buf_.clear();
        return;
      }

      if (buf_ == "OPTIONS") {
        on_method_cb_(HTTPMessage::M_OPTIONS);
        buf_.clear();
        return;
      }

      if (buf_ == "POST") {
        on_method_cb_(HTTPMessage::M_POST);
        buf_.clear();
        return;
      }

      if (buf_ == "PUT") {
        on_method_cb_(HTTPMessage::M_PUT);
        buf_.clear();
        return;
      }

      if (buf_ == "TRACE"){
        on_method_cb_(HTTPMessage::M_TRACE);
        buf_.clear();
        return;
      }

      RAISEF(kParseError, "Invalid HTTP method: $0", buf_.toString());
    }
  }

  if (buf_.size() > kMaxMethodSize) {
    RAISEF(kParseError, "HTTP method too large, max is $0", kMaxMethodSize);
  }
}

void HTTPParser::parseURI(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    if (on_uri_cb_) {
      on_uri_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_REQ_VERSION;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxURISize) {
    RAISEF(kParseError, "HTTP URI too large, max is $0", kMaxURISize);
  }
}

void HTTPParser::parseRequestVersion(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (on_version_cb_) {
      on_version_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_HEADER;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseResponseVersion(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    if (strncasecmp((char *) buf_.data(), "HTTP/1.0", buf_.size()) == 0) {
      body_bytes_expected_ = -1;
    }

    if (on_version_cb_) {
      on_version_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_RES_STATUS_CODE;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseResponseStatusCode(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    std::string status_code_str((char *) buf_.data(), buf_.size());
    int status_code = 1;

    try {
      status_code = std::stoi(status_code_str);
    } catch (const std::exception& e) {
      RAISEF(kParseError, "invalid http status code: $0", status_code_str);
    }

    if (on_status_code_cb_) {
      on_status_code_cb_(status_code);
    }

    buf_.clear();
    state_ = S_RES_STATUS_NAME;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxURISize) {
    RAISEF(kParseError, "HTTP URI too large, max is $0", kMaxURISize);
  }
}

void HTTPParser::parseResponseStatusName(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (on_status_name_cb_) {
      on_status_name_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_HEADER;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseHeader(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (buf_.size() > 0) {
      auto hkey = (char*) buf_.data();
      auto hkey_len = buf_.find(':');
      if (hkey_len == Buffer::npos) {
        RAISEF(kParseError, "invalid HTTP header line: $0", buf_.toString());
      }

      auto hval = hkey + hkey_len + 1;
      auto hval_len = buf_.size() - hkey_len - 1;
      while (hval_len > 0 && *hval == ' ') {
        hval++;
        hval_len--;
      }

      processHeader(hkey, hkey_len, hval, hval_len);
      buf_.clear();
      state_ = S_HEADER;
    } else {
      if (body_bytes_expected_ == 0) {
        state_ = S_DONE;
      } else {
        state_ = S_BODY;
      }

      if (on_headers_complete_cb_) {
        on_headers_complete_cb_();
      }
    }

    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxHeaderSize) {
    RAISEF(kParseError, "HTTP header too large, max is $0", kMaxHeaderSize);
  }
}

void HTTPParser::processHeader(
    const char* key,
    size_t key_len,
    const char* val,
    size_t val_len) {
  if (expect_body_ &&
      key_len == strlen(kContentLengthHeader) &&
      strncasecmp(key, kContentLengthHeader, key_len) == 0) {
    std::string content_length_str(val, val_len);
    try {
      body_bytes_expected_ = std::stoul(content_length_str);
    } catch (const std::exception& e) {
      RAISEF(kParseError, "invalid content length: $0", content_length_str);
    }
  }

  if (mode_ == PARSE_HTTP_RESPONSE &&
      expect_body_ &&
      key_len == strlen(kConnectionHeader) &&
      strncasecmp(key, kConnectionHeader, key_len) == 0 &&
      val_len == strlen("Close") &&
      strncasecmp(val, "Close", val_len) == 0) {
    body_bytes_expected_ = -1;
  }

  if (on_header_cb_) {
    on_header_cb_(key, key_len, val, val_len);
  }
}

void HTTPParser::readBody(const char** begin, const char* end) {
  body_bytes_read_ += end - *begin;

  if (body_bytes_read_ == body_bytes_expected_) {
    state_ = HTTPParser::S_DONE;
  }

  //if ((body_bytes_read_ > body_bytes_expected_) &&
  //    !(body_bytes_expected_ == 0 && mode_ == PARSE_HTTP_RESPONSE)) {
  //  RAISE(kParseError, "invalid trailing body bytes");
  //}

  if (on_body_chunk_cb_) {
    on_body_chunk_cb_(*begin, end - *begin);
  }

  *begin = end;
}

bool HTTPParser::readUntil(const char** begin, const char* end, char search) {
  auto cur = *begin;
  for (; cur < end && *cur != search; ++cur);
  buf_.append(*begin, (cur - *begin));
  *begin = cur;
  return cur != end && *cur == search;
}

void HTTPParser::reset() {
  switch (mode_) {
    case PARSE_HTTP_REQUEST:
      state_ = S_REQ_METHOD;
      break;

    case PARSE_HTTP_RESPONSE:
      state_ = S_RES_VERSION;
      break;
  }

  buf_.clear();
  body_bytes_read_ = 0;
  body_bytes_expected_ = 0;
  expect_body_ = true;
}

void HTTPParser::ignoreBody() {
  expect_body_ = false;
}

}
}
<|endoftext|>


<commit_before>/*
 *  Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield.
 *  This version only offers minimal wrapping of socket.c/socket.h
 *  Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/
 *
 * MIT License:
 * Copyright (c) 2008 Bjoern Hartmann
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * bjoern@cs.stanford.edu 12/30/2008
 */

#include "utility/w5100.h"
#include "utility/socket.h"
#include "Ethernet.h"
#include "Udp.h"
#include "Dns.h"

/* Constructor */
EthernetUDP::EthernetUDP() : _sock(MAX_SOCK_NUM) {}

/* Start EthernetUDP socket, listening at local port PORT */
uint8_t EthernetUDP::begin(uint16_t port) {
  if (_sock != MAX_SOCK_NUM)
    return 0;

  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    uint8_t s = socketStatus(i);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
      _sock = i;
      break;
    }
  }

  if (_sock == MAX_SOCK_NUM)
    return 0;

  _port = port;
  _remaining = 0;
  socket(_sock, SnMR::UDP, _port, 0);

  return 1;
}

/* return number of bytes available in the current packet,
   will return zero if parsePacket hasn't been called yet */
int EthernetUDP::available() {
  return _remaining;
}

/* Release any resources being used by this EthernetUDP instance */
void EthernetUDP::stop()
{
  if (_sock == MAX_SOCK_NUM)
    return;

  close(_sock);

  EthernetClass::_server_port[_sock] = 0;
  _sock = MAX_SOCK_NUM;
}

int EthernetUDP::beginPacket(const char *host, uint16_t port)
{
  // Look up the host first
  int ret = 0;
  DNSClient dns;
  IPAddress remote_addr;

  dns.begin(Ethernet.dnsServerIP());
  ret = dns.getHostByName(host, remote_addr);
  if (ret == 1) {
    return beginPacket(remote_addr, port);
  } else {
    return ret;
  }
}

int EthernetUDP::beginPacket(IPAddress ip, uint16_t port)
{
  _offset = 0;
  return startUDP(_sock, rawIPAddress(ip), port);
}

int EthernetUDP::endPacket()
{
  return sendUDP(_sock);
}

size_t EthernetUDP::write(uint8_t byte)
{
  return write(&byte, 1);
}

size_t EthernetUDP::write(const uint8_t *buffer, size_t size)
{
  uint16_t bytes_written = bufferData(_sock, _offset, buffer, size);
  _offset += bytes_written;
  return bytes_written;
}

int EthernetUDP::parsePacket()
{
  // discard any remaining bytes in the last packet
  flush();

  if (recvAvailable(_sock) > 0)
  {
    //HACK - hand-parse the UDP packet using TCP recv method
    uint8_t tmpBuf[8];
    int ret =0;
    //read 8 header bytes and get IP and port from it
    ret = recv(_sock,tmpBuf,8);
    if (ret > 0)
    {
      _remoteIP = tmpBuf;
      _remotePort = tmpBuf[4];
      _remotePort = (_remotePort << 8) + tmpBuf[5];
      _remaining = tmpBuf[6];
      _remaining = (_remaining << 8) + tmpBuf[7];

      // When we get here, any remaining bytes are the data
      ret = _remaining;
    }
    return ret;
  }
  // There aren't any packets available
  return 0;
}

int EthernetUDP::read()
{
  uint8_t byte;

  if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0))
  {
    // We read things without any problems
    _remaining--;
    return byte;
  }

  // If we get here, there's no data available
  return -1;
}

int EthernetUDP::read(unsigned char* buffer, size_t len)
{

  if (_remaining > 0)
  {

    int got;

    if (_remaining <= len)
    {
      // data should fit in the buffer
      got = recv(_sock, buffer, _remaining);
    }
    else
    {
      // too much data for the buffer,
      // grab as much as will fit
      got = recv(_sock, buffer, len);
    }

    if (got > 0)
    {
      _remaining -= got;
      return got;
    }

  }

  // If we get here, there's no data available or recv failed
  return -1;

}

int EthernetUDP::peek()
{
  uint8_t b;
  // Unlike recv, peek doesn't check to see if there's any data available, so we must.
  // If the user hasn't called parsePacket yet then return nothing otherwise they
  // may get the UDP header
  if (!_remaining)
    return -1;
  ::peek(_sock, &b);
  return b;
}

void EthernetUDP::flush()
{
  // could this fail (loop endlessly) if _remaining > 0 and recv in read fails?
  // should only occur if recv fails after telling us the data is there, lets
  // hope the w5100 always behaves :)

  while (_remaining)
  {
    read();
  }
}

/* Start EthernetUDP socket, listening at local port PORT */
uint8_t EthernetUDP::beginMulticast(IPAddress ip, uint16_t port)
{
  if (_sock != MAX_SOCK_NUM)
    return 0;

  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    uint8_t s = W5100.readSnSR(i);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
      _sock = i;
      break;
    }
  }

  if (_sock == MAX_SOCK_NUM)
    return 0;

  // Calculate MAC address from Multicast IP Address
  byte mac[] = {  0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 };

  mac[3] = ip[1] & 0x7F;
  mac[4] = ip[2];
  mac[5] = ip[3];

  W5100.writeSnDIPR(_sock, rawIPAddress(ip));   //239.255.0.1
  W5100.writeSnDPORT(_sock, port);
  W5100.writeSnDHAR(_sock,mac);

  _remaining = 0;
  socket(_sock, SnMR::UDP, port, SnMR::MULTI);
  return 1;
}

<commit_msg>Ethernet: partially fix flush() behaviour in EthernetUDP<commit_after>/*
 *  Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield.
 *  This version only offers minimal wrapping of socket.c/socket.h
 *  Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/
 *
 * MIT License:
 * Copyright (c) 2008 Bjoern Hartmann
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * bjoern@cs.stanford.edu 12/30/2008
 */

#include "utility/w5100.h"
#include "utility/socket.h"
#include "Ethernet.h"
#include "Udp.h"
#include "Dns.h"

/* Constructor */
EthernetUDP::EthernetUDP() : _sock(MAX_SOCK_NUM) {}

/* Start EthernetUDP socket, listening at local port PORT */
uint8_t EthernetUDP::begin(uint16_t port) {
  if (_sock != MAX_SOCK_NUM)
    return 0;

  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    uint8_t s = socketStatus(i);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
      _sock = i;
      break;
    }
  }

  if (_sock == MAX_SOCK_NUM)
    return 0;

  _port = port;
  _remaining = 0;
  socket(_sock, SnMR::UDP, _port, 0);

  return 1;
}

/* return number of bytes available in the current packet,
   will return zero if parsePacket hasn't been called yet */
int EthernetUDP::available() {
  return _remaining;
}

/* Release any resources being used by this EthernetUDP instance */
void EthernetUDP::stop()
{
  if (_sock == MAX_SOCK_NUM)
    return;

  close(_sock);

  EthernetClass::_server_port[_sock] = 0;
  _sock = MAX_SOCK_NUM;
}

int EthernetUDP::beginPacket(const char *host, uint16_t port)
{
  // Look up the host first
  int ret = 0;
  DNSClient dns;
  IPAddress remote_addr;

  dns.begin(Ethernet.dnsServerIP());
  ret = dns.getHostByName(host, remote_addr);
  if (ret == 1) {
    return beginPacket(remote_addr, port);
  } else {
    return ret;
  }
}

int EthernetUDP::beginPacket(IPAddress ip, uint16_t port)
{
  _offset = 0;
  return startUDP(_sock, rawIPAddress(ip), port);
}

int EthernetUDP::endPacket()
{
  return sendUDP(_sock);
}

size_t EthernetUDP::write(uint8_t byte)
{
  return write(&byte, 1);
}

size_t EthernetUDP::write(const uint8_t *buffer, size_t size)
{
  uint16_t bytes_written = bufferData(_sock, _offset, buffer, size);
  _offset += bytes_written;
  return bytes_written;
}

int EthernetUDP::parsePacket()
{
  // discard any remaining bytes in the last packet
  while (_remaining) {
    // could this fail (loop endlessly) if _remaining > 0 and recv in read fails?
    // should only occur if recv fails after telling us the data is there, lets
    // hope the w5100 always behaves :)
    read();
  }

  if (recvAvailable(_sock) > 0)
  {
    //HACK - hand-parse the UDP packet using TCP recv method
    uint8_t tmpBuf[8];
    int ret =0;
    //read 8 header bytes and get IP and port from it
    ret = recv(_sock,tmpBuf,8);
    if (ret > 0)
    {
      _remoteIP = tmpBuf;
      _remotePort = tmpBuf[4];
      _remotePort = (_remotePort << 8) + tmpBuf[5];
      _remaining = tmpBuf[6];
      _remaining = (_remaining << 8) + tmpBuf[7];

      // When we get here, any remaining bytes are the data
      ret = _remaining;
    }
    return ret;
  }
  // There aren't any packets available
  return 0;
}

int EthernetUDP::read()
{
  uint8_t byte;

  if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0))
  {
    // We read things without any problems
    _remaining--;
    return byte;
  }

  // If we get here, there's no data available
  return -1;
}

int EthernetUDP::read(unsigned char* buffer, size_t len)
{

  if (_remaining > 0)
  {

    int got;

    if (_remaining <= len)
    {
      // data should fit in the buffer
      got = recv(_sock, buffer, _remaining);
    }
    else
    {
      // too much data for the buffer,
      // grab as much as will fit
      got = recv(_sock, buffer, len);
    }

    if (got > 0)
    {
      _remaining -= got;
      return got;
    }

  }

  // If we get here, there's no data available or recv failed
  return -1;

}

int EthernetUDP::peek()
{
  uint8_t b;
  // Unlike recv, peek doesn't check to see if there's any data available, so we must.
  // If the user hasn't called parsePacket yet then return nothing otherwise they
  // may get the UDP header
  if (!_remaining)
    return -1;
  ::peek(_sock, &b);
  return b;
}

void EthernetUDP::flush()
{
  // TODO: we should wait for TX buffer to be emptied
}

/* Start EthernetUDP socket, listening at local port PORT */
uint8_t EthernetUDP::beginMulticast(IPAddress ip, uint16_t port)
{
  if (_sock != MAX_SOCK_NUM)
    return 0;

  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    uint8_t s = W5100.readSnSR(i);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
      _sock = i;
      break;
    }
  }

  if (_sock == MAX_SOCK_NUM)
    return 0;

  // Calculate MAC address from Multicast IP Address
  byte mac[] = {  0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 };

  mac[3] = ip[1] & 0x7F;
  mac[4] = ip[2];
  mac[5] = ip[3];

  W5100.writeSnDIPR(_sock, rawIPAddress(ip));   //239.255.0.1
  W5100.writeSnDPORT(_sock, port);
  W5100.writeSnDHAR(_sock,mac);

  _remaining = 0;
  socket(_sock, SnMR::UDP, port, SnMR::MULTI);
  return 1;
}

<|endoftext|>


<commit_before><commit_msg>Check.<commit_after><|endoftext|>