<commit_before>/*
	This file is part of solidity.

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

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

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2016
 * Solidity inline assembly parser.
 */

#include <libsolidity/inlineasm/AsmParser.h>
#include <ctype.h>
#include <algorithm>
#include <libsolidity/parsing/Scanner.h>

using namespace std;
using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::assembly;

shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
{
	try
	{
		m_scanner = _scanner;
		return make_shared<Block>(parseBlock());
	}
	catch (FatalError const&)
	{
		if (m_errors.empty())
			throw; // Something is weird here, rather throw again.
	}
	return nullptr;
}

assembly::Block Parser::parseBlock()
{
	assembly::Block block = createWithLocation<Block>();
	expectToken(Token::LBrace);
	while (m_scanner->currentToken() != Token::RBrace)
		block.statements.emplace_back(parseStatement());
	block.location.end = endPosition();
	m_scanner->next();
	return block;
}

assembly::Statement Parser::parseStatement()
{
	switch (m_scanner->currentToken())
	{
	case Token::Let:
		return parseVariableDeclaration();
	case Token::Function:
		return parseFunctionDefinition();
	case Token::LBrace:
		return parseBlock();
	case Token::Assign:
	{
		assembly::Assignment assignment = createWithLocation<assembly::Assignment>();
		m_scanner->next();
		expectToken(Token::Colon);
		assignment.variableName.location = location();
		assignment.variableName.name = m_scanner->currentLiteral();
		if (instructions().count(assignment.variableName.name))
			fatalParserError("Identifier expected, got instruction name.");
		assignment.location.end = endPosition();
		expectToken(Token::Identifier);
		return assignment;
	}
	case Token::Return: // opcode
	case Token::Byte: // opcode
	default:
		break;
	}
	// Options left:
	// Simple instruction (might turn into functional),
	// literal,
	// identifier (might turn into label or functional assignment)
	Statement statement(parseElementaryOperation());
	switch (m_scanner->currentToken())
	{
	case Token::LParen:
		return parseFunctionalInstruction(std::move(statement));
	case Token::Colon:
	{
		if (statement.type() != typeid(assembly::Identifier))
			fatalParserError("Label name / variable name must precede \":\".");
		assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
		m_scanner->next();
		// identifier:=: should be parsed as identifier: =: (i.e. a label),
		// while identifier:= (being followed by a non-colon) as identifier := (assignment).
		if (m_scanner->currentToken() == Token::Assign && m_scanner->peekNextToken() != Token::Colon)
		{
			// functional assignment
			FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location);
			if (instructions().count(identifier.name))
				fatalParserError("Cannot use instruction names for identifier names.");
			m_scanner->next();
			funAss.variableName = identifier;
			funAss.value.reset(new Statement(parseExpression()));
			funAss.location.end = locationOf(*funAss.value).end;
			return funAss;
		}
		else
		{
			// label
			Label label = createWithLocation<Label>(identifier.location);
			label.name = identifier.name;
			return label;
		}
	}
	default:
		break;
	}
	return statement;
}

assembly::Statement Parser::parseExpression()
{
	Statement operation = parseElementaryOperation(true);
	if (m_scanner->currentToken() == Token::LParen)
		return parseFunctionalInstruction(std::move(operation));
	else
		return operation;
}

std::map<string, dev::solidity::Instruction> const& Parser::instructions()
{
	// Allowed instructions, lowercase names.
	static map<string, dev::solidity::Instruction> s_instructions;
	if (s_instructions.empty())
	{
		for (auto const& instruction: solidity::c_instructions)
		{
			if (
				instruction.second == solidity::Instruction::JUMPDEST ||
				(solidity::Instruction::PUSH1 <= instruction.second && instruction.second <= solidity::Instruction::PUSH32)
			)
				continue;
			string name = instruction.first;
			transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
			s_instructions[name] = instruction.second;
		}

		// add alias for suicide
		s_instructions["suicide"] = solidity::Instruction::SELFDESTRUCT;
	}
	return s_instructions;
}

assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
{
	Statement ret;
	switch (m_scanner->currentToken())
	{
	case Token::Identifier:
	case Token::Return:
	case Token::Byte:
	case Token::Address:
	{
		string literal;
		if (m_scanner->currentToken() == Token::Return)
			literal = "return";
		else if (m_scanner->currentToken() == Token::Byte)
			literal = "byte";
		else if (m_scanner->currentToken() == Token::Address)
			literal = "address";
		else
			literal = m_scanner->currentLiteral();
		// first search the set of instructions.
		if (instructions().count(literal))
		{
			dev::solidity::Instruction const& instr = instructions().at(literal);
			if (_onlySinglePusher)
			{
				InstructionInfo info = dev::solidity::instructionInfo(instr);
				if (info.ret != 1)
					fatalParserError("Instruction " + info.name + " not allowed in this context.");
			}
			ret = Instruction{location(), instr};
		}
		else
			ret = Identifier{location(), literal};
		break;
	}
	case Token::StringLiteral:
	case Token::Number:
	{
		ret = Literal{
			location(),
			m_scanner->currentToken() == Token::Number,
			m_scanner->currentLiteral()
		};
		break;
	}
	default:
		fatalParserError("Expected elementary inline assembly operation.");
	}
	m_scanner->next();
	return ret;
}

assembly::VariableDeclaration Parser::parseVariableDeclaration()
{
	VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
	expectToken(Token::Let);
	varDecl.name = expectAsmIdentifier();
	expectToken(Token::Colon);
	expectToken(Token::Assign);
	varDecl.value.reset(new Statement(parseExpression()));
	varDecl.location.end = locationOf(*varDecl.value).end;
	return varDecl;
}

assembly::FunctionDefinition Parser::parseFunctionDefinition()
{
	FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
	expectToken(Token::Function);
	funDef.name = expectAsmIdentifier();
	expectToken(Token::LParen);
	while (m_scanner->currentToken() != Token::RParen)
	{
		funDef.arguments.push_back(expectAsmIdentifier());
		if (m_scanner->currentToken() == Token::RParen)
			break;
		expectToken(Token::Comma);
	}
	expectToken(Token::RParen);
	if (m_scanner->currentToken() == Token::Sub)
	{
		expectToken(Token::Sub);
		expectToken(Token::GreaterThan);
		while (true)
		{
			funDef.returns.push_back(expectAsmIdentifier());
			if (m_scanner->currentToken() == Token::LBrace)
				break;
			expectToken(Token::Comma);
		}
	}
	funDef.body = parseBlock();
	funDef.location.end = funDef.body.location.end;
	return funDef;
}

assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
{
	if (_instruction.type() == typeid(Instruction))
	{
		FunctionalInstruction ret;
		ret.instruction = std::move(boost::get<Instruction>(_instruction));
		ret.location = ret.instruction.location;
		solidity::Instruction instr = ret.instruction.instruction;
		InstructionInfo instrInfo = instructionInfo(instr);
		if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16)
			fatalParserError("DUPi instructions not allowed for functional notation");
		if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16)
			fatalParserError("SWAPi instructions not allowed for functional notation");
		expectToken(Token::LParen);
		unsigned args = unsigned(instrInfo.args);
		for (unsigned i = 0; i < args; ++i)
		{
			ret.arguments.emplace_back(parseExpression());
			if (i != args - 1)
			{
				if (m_scanner->currentToken() != Token::Comma)
					fatalParserError(string(
						"Expected comma (" +
						instrInfo.name +
						" expects " +
						boost::lexical_cast<string>(args) +
						" arguments)"
					));
				else
					m_scanner->next();
			}
		}
		ret.location.end = endPosition();
		if (m_scanner->currentToken() == Token::Comma)
			fatalParserError(
				string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)")
			);
		expectToken(Token::RParen);
		return ret;
	}
	else if (_instruction.type() == typeid(Identifier))
	{
		FunctionCall ret;
		ret.functionName = std::move(boost::get<Identifier>(_instruction));
		ret.location = ret.functionName.location;
		expectToken(Token::LParen);
		while (m_scanner->currentToken() != Token::RParen)
		{
			ret.arguments.emplace_back(parseExpression());
			if (m_scanner->currentToken() == Token::RParen)
				break;
			expectToken(Token::Comma);
		}
		ret.location.end = endPosition();
		expectToken(Token::RParen);
		return ret;
	}
	else
		fatalParserError("Assembly instruction or function name required in front of \"(\")");

	return {};
}

string Parser::expectAsmIdentifier()
{
	string name = m_scanner->currentLiteral();
	if (instructions().count(name))
		fatalParserError("Cannot use instruction names for identifier names.");
	expectToken(Token::Identifier);
	return name;
}
<commit_msg>Do not validate identifiers against EVM instructions in JULIA<commit_after>/*
	This file is part of solidity.

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

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

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2016
 * Solidity inline assembly parser.
 */

#include <libsolidity/inlineasm/AsmParser.h>
#include <ctype.h>
#include <algorithm>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/interface/Exceptions.h>

using namespace std;
using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::assembly;

shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
{
	try
	{
		m_scanner = _scanner;
		return make_shared<Block>(parseBlock());
	}
	catch (FatalError const&)
	{
		if (m_errors.empty())
			throw; // Something is weird here, rather throw again.
	}
	return nullptr;
}

assembly::Block Parser::parseBlock()
{
	assembly::Block block = createWithLocation<Block>();
	expectToken(Token::LBrace);
	while (m_scanner->currentToken() != Token::RBrace)
		block.statements.emplace_back(parseStatement());
	block.location.end = endPosition();
	m_scanner->next();
	return block;
}

assembly::Statement Parser::parseStatement()
{
	switch (m_scanner->currentToken())
	{
	case Token::Let:
		return parseVariableDeclaration();
	case Token::Function:
		return parseFunctionDefinition();
	case Token::LBrace:
		return parseBlock();
	case Token::Assign:
	{
		assembly::Assignment assignment = createWithLocation<assembly::Assignment>();
		m_scanner->next();
		expectToken(Token::Colon);
		assignment.variableName.location = location();
		assignment.variableName.name = m_scanner->currentLiteral();
		if (!m_julia && instructions().count(assignment.variableName.name))
			fatalParserError("Identifier expected, got instruction name.");
		assignment.location.end = endPosition();
		expectToken(Token::Identifier);
		return assignment;
	}
	case Token::Return: // opcode
	case Token::Byte: // opcode
	default:
		break;
	}
	// Options left:
	// Simple instruction (might turn into functional),
	// literal,
	// identifier (might turn into label or functional assignment)
	Statement statement(parseElementaryOperation());
	switch (m_scanner->currentToken())
	{
	case Token::LParen:
		return parseFunctionalInstruction(std::move(statement));
	case Token::Colon:
	{
		if (statement.type() != typeid(assembly::Identifier))
			fatalParserError("Label name / variable name must precede \":\".");
		assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
		m_scanner->next();
		// identifier:=: should be parsed as identifier: =: (i.e. a label),
		// while identifier:= (being followed by a non-colon) as identifier := (assignment).
		if (m_scanner->currentToken() == Token::Assign && m_scanner->peekNextToken() != Token::Colon)
		{
			// functional assignment
			FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location);
			if (!m_julia && instructions().count(identifier.name))
				fatalParserError("Cannot use instruction names for identifier names.");
			m_scanner->next();
			funAss.variableName = identifier;
			funAss.value.reset(new Statement(parseExpression()));
			funAss.location.end = locationOf(*funAss.value).end;
			return funAss;
		}
		else
		{
			// label
			Label label = createWithLocation<Label>(identifier.location);
			label.name = identifier.name;
			return label;
		}
	}
	default:
		break;
	}
	return statement;
}

assembly::Statement Parser::parseExpression()
{
	Statement operation = parseElementaryOperation(true);
	if (m_scanner->currentToken() == Token::LParen)
		return parseFunctionalInstruction(std::move(operation));
	else
		return operation;
}

std::map<string, dev::solidity::Instruction> const& Parser::instructions()
{
	// Allowed instructions, lowercase names.
	static map<string, dev::solidity::Instruction> s_instructions;
	if (s_instructions.empty())
	{
		for (auto const& instruction: solidity::c_instructions)
		{
			if (
				instruction.second == solidity::Instruction::JUMPDEST ||
				(solidity::Instruction::PUSH1 <= instruction.second && instruction.second <= solidity::Instruction::PUSH32)
			)
				continue;
			string name = instruction.first;
			transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
			s_instructions[name] = instruction.second;
		}

		// add alias for suicide
		s_instructions["suicide"] = solidity::Instruction::SELFDESTRUCT;
	}
	return s_instructions;
}

assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
{
	Statement ret;
	switch (m_scanner->currentToken())
	{
	case Token::Identifier:
	case Token::Return:
	case Token::Byte:
	case Token::Address:
	{
		string literal;
		if (m_scanner->currentToken() == Token::Return)
			literal = "return";
		else if (m_scanner->currentToken() == Token::Byte)
			literal = "byte";
		else if (m_scanner->currentToken() == Token::Address)
			literal = "address";
		else
			literal = m_scanner->currentLiteral();
		// first search the set of instructions.
		if (!m_julia && instructions().count(literal))
		{
			dev::solidity::Instruction const& instr = instructions().at(literal);
			if (_onlySinglePusher)
			{
				InstructionInfo info = dev::solidity::instructionInfo(instr);
				if (info.ret != 1)
					fatalParserError("Instruction " + info.name + " not allowed in this context.");
			}
			ret = Instruction{location(), instr};
		}
		else
			ret = Identifier{location(), literal};
		break;
	}
	case Token::StringLiteral:
	case Token::Number:
	{
		ret = Literal{
			location(),
			m_scanner->currentToken() == Token::Number,
			m_scanner->currentLiteral()
		};
		break;
	}
	default:
		fatalParserError("Expected elementary inline assembly operation.");
	}
	m_scanner->next();
	return ret;
}

assembly::VariableDeclaration Parser::parseVariableDeclaration()
{
	VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
	expectToken(Token::Let);
	varDecl.name = expectAsmIdentifier();
	expectToken(Token::Colon);
	expectToken(Token::Assign);
	varDecl.value.reset(new Statement(parseExpression()));
	varDecl.location.end = locationOf(*varDecl.value).end;
	return varDecl;
}

assembly::FunctionDefinition Parser::parseFunctionDefinition()
{
	FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
	expectToken(Token::Function);
	funDef.name = expectAsmIdentifier();
	expectToken(Token::LParen);
	while (m_scanner->currentToken() != Token::RParen)
	{
		funDef.arguments.push_back(expectAsmIdentifier());
		if (m_scanner->currentToken() == Token::RParen)
			break;
		expectToken(Token::Comma);
	}
	expectToken(Token::RParen);
	if (m_scanner->currentToken() == Token::Sub)
	{
		expectToken(Token::Sub);
		expectToken(Token::GreaterThan);
		while (true)
		{
			funDef.returns.push_back(expectAsmIdentifier());
			if (m_scanner->currentToken() == Token::LBrace)
				break;
			expectToken(Token::Comma);
		}
	}
	funDef.body = parseBlock();
	funDef.location.end = funDef.body.location.end;
	return funDef;
}

assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
{
	if (_instruction.type() == typeid(Instruction))
	{
		solAssert(!m_julia, "Instructions are invalid in JULIA");
		FunctionalInstruction ret;
		ret.instruction = std::move(boost::get<Instruction>(_instruction));
		ret.location = ret.instruction.location;
		solidity::Instruction instr = ret.instruction.instruction;
		InstructionInfo instrInfo = instructionInfo(instr);
		if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16)
			fatalParserError("DUPi instructions not allowed for functional notation");
		if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16)
			fatalParserError("SWAPi instructions not allowed for functional notation");
		expectToken(Token::LParen);
		unsigned args = unsigned(instrInfo.args);
		for (unsigned i = 0; i < args; ++i)
		{
			ret.arguments.emplace_back(parseExpression());
			if (i != args - 1)
			{
				if (m_scanner->currentToken() != Token::Comma)
					fatalParserError(string(
						"Expected comma (" +
						instrInfo.name +
						" expects " +
						boost::lexical_cast<string>(args) +
						" arguments)"
					));
				else
					m_scanner->next();
			}
		}
		ret.location.end = endPosition();
		if (m_scanner->currentToken() == Token::Comma)
			fatalParserError(
				string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)")
			);
		expectToken(Token::RParen);
		return ret;
	}
	else if (_instruction.type() == typeid(Identifier))
	{
		FunctionCall ret;
		ret.functionName = std::move(boost::get<Identifier>(_instruction));
		ret.location = ret.functionName.location;
		expectToken(Token::LParen);
		while (m_scanner->currentToken() != Token::RParen)
		{
			ret.arguments.emplace_back(parseExpression());
			if (m_scanner->currentToken() == Token::RParen)
				break;
			expectToken(Token::Comma);
		}
		ret.location.end = endPosition();
		expectToken(Token::RParen);
		return ret;
	}
	else
		fatalParserError("Assembly instruction or function name required in front of \"(\")");

	return {};
}

string Parser::expectAsmIdentifier()
{
	string name = m_scanner->currentLiteral();
	if (!m_julia && instructions().count(name))
		fatalParserError("Cannot use instruction names for identifier names.");
	expectToken(Token::Identifier);
	return name;
}
<|endoftext|>


<commit_before>#include "map.h"

const char *WaterTilePath::path = "res/tiles/water.png";

Map::Map() {}

Map::Map(int height, int width) :
    height(height),
    width(width),
    matrix(height, std::vector<std::shared_ptr<Drawable> >(width))
{
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; ++j) {
            matrix[i][j] = std::make_shared<WaterTile>();
        }
    }
}

void Map::draw(Camera &camera) {
    // FIXME this is not the right place for this
    al_clear_to_color(al_map_rgb(0, 0, 0));
    camera.set_transform_map();
    int tile_size = 512; // TODO unhardcode
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; ++j) {
            matrix[i][j]->draw(i * tile_size, j * tile_size);
        }
    }
}
<commit_msg>Infinite map<commit_after>#include "map.h"

const char *WaterTilePath::path = "res/tiles/water.png";

Map::Map() {}

Map::Map(int height, int width) :
    height(height),
    width(width),
    matrix(height, std::vector<std::shared_ptr<Drawable> >(width))
{
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; ++j) {
            matrix[i][j] = std::make_shared<WaterTile>();
        }
    }
}

void Map::draw(Camera &camera) {
    // FIXME this is not the right place for this
    al_clear_to_color(al_map_rgb(0, 0, 0));
    camera.set_transform_map();
    int tile_size = 512; // TODO unhardcode
    // number of tile column where the camera is centered
    int cam_tile_x = camera.get_pos_x() / tile_size;
    // number of tile row where the camera is centered
    int cam_tile_y = camera.get_pos_y() / tile_size;
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; ++j) {
            /* Infinite map.
             * Wraps map rows and columns module width and height respectively,
             * closest tho cam_tile_x and cam_tile_y.
             * That is, draw width / 2 columns to the left and width / 2 to the
             * right (+-1), and the same with rows.
             */
            int x = j + (cam_tile_x / width) * width;
            if (x < cam_tile_x - width / 2) {
                x += width;
            }
            if (x > cam_tile_x + width / 2) {
                x -= width;
            }
            int y = i + (cam_tile_y / height) * height;
            if (y < cam_tile_y - height / 2) {
                y += height;
            }
            if (y > cam_tile_y + height / 2) {
                y -= height;
            }
            matrix[i][j]->draw(x * tile_size, y * tile_size);
        }
    }
}
<|endoftext|>


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

/*
 * XSEC
 *
 * XSECAutoPtr := internal classes for RAII handling of transcoded data
 *
 * Author(s): Scott Cantor
 *
 * $Id:$
 *
 */

#ifndef XSECAUTOPTR_INCLUDE
#define XSECAUTOPTR_INCLUDE

#include <xsec/framework/XSECDefs.hpp>
#include <xercesc/util/XMLString.hpp>

XSEC_USING_XERCES(XMLString);

/**
 * \addtogroup internal
 * @{
 */

 /**
  * A minimal auto_ptr-like class that can copy or transcode a buffer into
  * the local code page and free the result automatically.
  *
  * Needed because a standard auto_ptr would use delete on the resulting
  * pointer.
  */
class XSECAutoPtrChar
{
    XSECAutoPtrChar(const XSECAutoPtrChar&);
    XSECAutoPtrChar& operator=(const XSECAutoPtrChar&);
public:
    XSECAutoPtrChar() : m_buf(nullptr) {
    }

    XSECAutoPtrChar(const XMLCh* src) : m_buf(xercesc::XMLString::transcode(src)) {
    }

    XSECAutoPtrChar(const char* src) : m_buf(xercesc::XMLString::replicate(src)) {
    }

    ~XSECAutoPtrChar() {
        xercesc::XMLString::release(&m_buf);
    }

    const char* get() const {
        return m_buf;
    }

    char* release() {
        char* temp=m_buf; m_buf=nullptr; return temp;
    }

private:
    char* m_buf;
};

/**
 * A minimal auto_ptr-like class that can copy or transcode a buffer into
 * 16-bit Unicode and free the result automatically.
 *
 * Needed because a standard auto_ptr would use delete on the resulting
 * pointer.
 */
class XSECAutoPtrXMLCh
{
    XSECAutoPtrXMLCh(const XSECAutoPtrXMLCh&);
    XSECAutoPtrXMLCh& operator=(const XSECAutoPtrXMLCh&);
public:
    XSECAutoPtrXMLCh() : m_buf(nullptr) {
    }

    XSECAutoPtrXMLCh(const char* src) : m_buf(xercesc::XMLString::transcode(src)) {
    }

    XSECAutoPtrXMLCh(const XMLCh* src) : m_buf(xercesc::XMLString::replicate(src)) {
    }

    ~XSECAutoPtrXMLCh() {
        xercesc::XMLString::release(&m_buf);
    }

    const XMLCh* get() const {
        return m_buf;
    }

    XMLCh* release() {
        XMLCh* temp=m_buf; m_buf=nullptr; return temp;
    }

private:
    XMLCh* m_buf;
};

/** @} */

#endif /* XSECAUTOPTR_INCLUDE */

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

/*
 * XSEC
 *
 * XSECAutoPtr := internal classes for RAII handling of transcoded data
 *
 * Author(s): Scott Cantor
 *
 * $Id:$
 *
 */

#ifndef XSECAUTOPTR_INCLUDE
#define XSECAUTOPTR_INCLUDE

#include <xsec/framework/XSECDefs.hpp>
#include <xercesc/util/XMLString.hpp>

XSEC_USING_XERCES(XMLString);

/**
 * \addtogroup internal
 * @{
 */

 /**
  * A minimal auto_ptr-like class that can copy or transcode a buffer into
  * the local code page and free the result automatically.
  *
  * Needed because a standard auto_ptr would use delete on the resulting
  * pointer.
  */
class XSECAutoPtrChar
{
    XSECAutoPtrChar(const XSECAutoPtrChar&);
    XSECAutoPtrChar& operator=(const XSECAutoPtrChar&);
public:
    XSECAutoPtrChar() : m_buf(NULL) {
    }

    XSECAutoPtrChar(const XMLCh* src) : m_buf(xercesc::XMLString::transcode(src)) {
    }

    XSECAutoPtrChar(const char* src) : m_buf(xercesc::XMLString::replicate(src)) {
    }

    ~XSECAutoPtrChar() {
        xercesc::XMLString::release(&m_buf);
    }

    const char* get() const {
        return m_buf;
    }

    char* release() {
        char* temp=m_buf; m_buf=NULL; return temp;
    }

private:
    char* m_buf;
};

/**
 * A minimal auto_ptr-like class that can copy or transcode a buffer into
 * 16-bit Unicode and free the result automatically.
 *
 * Needed because a standard auto_ptr would use delete on the resulting
 * pointer.
 */
class XSECAutoPtrXMLCh
{
    XSECAutoPtrXMLCh(const XSECAutoPtrXMLCh&);
    XSECAutoPtrXMLCh& operator=(const XSECAutoPtrXMLCh&);
public:
    XSECAutoPtrXMLCh() : m_buf(NULL) {
    }

    XSECAutoPtrXMLCh(const char* src) : m_buf(xercesc::XMLString::transcode(src)) {
    }

    XSECAutoPtrXMLCh(const XMLCh* src) : m_buf(xercesc::XMLString::replicate(src)) {
    }

    ~XSECAutoPtrXMLCh() {
        xercesc::XMLString::release(&m_buf);
    }

    const XMLCh* get() const {
        return m_buf;
    }

    XMLCh* release() {
        XMLCh* temp=m_buf; m_buf=NULL; return temp;
    }

private:
    XMLCh* m_buf;
};

/** @} */

#endif /* XSECAUTOPTR_INCLUDE */

<|endoftext|>


<commit_before>#include <iostream>
#include "CaffeBatchPrediction.hpp"
#include "scalefactor.hpp"
#include "fast_nms.hpp"
#include "detect.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/gpu/gpu.hpp>

static double gtod_wrapper(void)
{
    struct timeval tv;

    gettimeofday(&tv, NULL);
    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}

// TODO :: Make a call for GPU Mat input.
// Simple multi-scale detect.  Take a single image, scale it into a number
// of diffent sized images. Run a fixed-size detection window across each
// of them.  Keep track of the scale of each scaled image to map the
// detected rectangles back to the correct location and size on the
// original input images
template<class MatT>
void NNDetect<MatT>::detectMultiscale(const cv::Mat&             inputImg,
                                      const cv::Mat&             depthMat,
                                      const cv::Size&            minSize,
                                      const cv::Size&            maxSize,
                                      double                     scaleFactor,
                                      const std::vector<double>& nmsThreshold,
                                      const std::vector<double>& detectThreshold,
                                      std::vector<cv::Rect>&     rectsOut)
{
    // Size of the first level classifier. Others are an integer multiple
    // of this initial size (2x and maybe 4x if we need it)
    int wsize = d12_.getInputGeometry().width;

    // scaled images which allow us to find images between min and max
    // size for the given classifier input window
    std::vector<std::pair<MatT, double> > scaledImages12;
    std::vector<std::pair<MatT, double> > scaledImages24;
    // Maybe later ? std::vector<std::pair<MatT, double> > scaledImages48;

    // list of windows to work with.
    // A window is a rectangle from a given scaled image along
    // with the index of the scaled image it corresponds with.
    std::vector<Window> windowsIn;
    std::vector<Window> windowsOut;

    // Confidence scores (0.0 - 1.0) for each detected rectangle
    std::vector<float> scores;

    // Generate a list of initial windows to search. Each window will be 12x12 from a scaled image
    // These scaled images let us search for variable sized objects using a fixed-width detector
    MatT f32Img;

    MatT(inputImg).convertTo(f32Img, CV_32FC3);     // classifier runs on float pixel data
    generateInitialWindows(f32Img, depthMat, minSize, maxSize, wsize, scaleFactor, scaledImages12, windowsIn);

    // Generate scaled images for the larger detect sizes as well. Subsequent passes will use larger
    // input sizes. These images will let us grab higher res input as the detector size goes up (as
    // opposed to just scaling up the 12x12 images to a larger size).
    scalefactor(f32Img, cv::Size(wsize * 2, wsize * 2), minSize, maxSize, scaleFactor, scaledImages24);
    // not yet - scalefactor(f32Img, cv::Size(wsize*4,wsize*4), minSize, maxSize, scaleFactor, scaledImages48);

    // Do 1st level of detection. This takes the initial list of windows
    // and returns the list which have a score for "ball" above the
    // threshold listed.
    std::cout << "d12 windows in = " << windowsIn.size() << std::endl;
    runDetection(d12_, scaledImages12, windowsIn, detectThreshold[0], "ball", windowsOut, scores);
    std::cout << "d12 windows out = " << windowsOut.size() << std::endl;
    runNMS(windowsOut, scores, scaledImages12, nmsThreshold[0], windowsIn);
    std::cout << "d12 nms windows out = " << windowsIn.size() << std::endl;

    // Double the size of the rects to get from a 12x12 to 24x24
    // detection window.  Use scaledImages24 for the detection call
    // since that has the scales appropriate for the 24x24 detector
    for (auto it = windowsIn.begin(); it != windowsIn.end(); ++it)
    {
        it->first = cv::Rect(it->first.x * 2, it->first.y * 2,
                             it->first.width * 2, it->first.height * 2);
    }

    if ((detectThreshold.size() > 1) && (detectThreshold[1] > 0.0))
    {
        std::cout << "d24 windows in = " << windowsIn.size() << std::endl;
        runDetection(d24_, scaledImages24, windowsIn, detectThreshold[1], "ball", windowsOut, scores);
        std::cout << "d24 windows out = " << windowsOut.size() << std::endl;
        runNMS(windowsOut, scores, scaledImages24, nmsThreshold[1], windowsIn);
		std::cout << "d24 nms windows out = " << windowsIn.size() << std::endl;
    }

    // Final result - scale the output rectangles back to the
    // correct scale for the original sized image
    rectsOut.clear();
    for (auto it = windowsIn.cbegin(); it != windowsIn.cend(); ++it)
    {
        double   scale = scaledImages24[it->second].second;
        std::cout << "Mid Depth at Scale: " << 192.9* pow(((float)wsize*(float)wsize*4)/((float)inputImg.rows*(float)inputImg.cols/(scale*scale)), -.534) << std::endl;
        cv::Rect rect(it->first);
        cv::Rect scaledRect(cv::Rect(rect.x / scale, rect.y / scale, rect.width / scale, rect.height / scale));
        rectsOut.push_back(scaledRect);

    }
}

template<class MatT>
void NNDetect<MatT>::runNMS(const std::vector<Window>& windows,
                            const std::vector<float>& scores,
                            const std::vector<std::pair<MatT, double> >& scaledImages,
                            double nmsThreshold,
                            std::vector<Window>& windowsOut)
{
    if ((nmsThreshold > 0.0) && (nmsThreshold < 1.0))
    {
        // Detected is a rect, score pair.
        std::vector<Detected> detected;

        // Need to scale each rect to the correct mapping to the
        // original image, since rectangles from multiple different
        // scales might overlap
        for (size_t i = 0; i < windows.size(); i++)
        {
            double   scale = scaledImages[windows[i].second].second;
            cv::Rect rect(windows[i].first);
            cv::Rect scaledRect(cv::Rect(rect.x / scale, rect.y / scale, rect.width / scale, rect.height / scale));
            detected.push_back(Detected(scaledRect, scores[i]));
        }

        std::vector<size_t> nmsOut;
        fastNMS(detected, nmsThreshold, nmsOut);
        // Each entry of nmsOut is the index of a saved rect/scales
        // pair.  Save the entries from those indexes as the output
        windowsOut.clear();
        for (auto it = nmsOut.cbegin(); it != nmsOut.cend(); ++it)
        {
            windowsOut.push_back(windows[*it]);
        }
    }
    else
    {
        // If not running NMS, output is the same as the input
        windowsOut = windows;
    }
}

template<class MatT>
void NNDetect<MatT>::generateInitialWindows(
    const MatT& input,
    const cv::Mat& depthIn,
    const cv::Size& minSize,
    const cv::Size& maxSize,
    int wsize,
    double scaleFactor,
    std::vector<std::pair<MatT, double> >& scaledImages,
    std::vector<Window>& windows)
{
    windows.clear();
    size_t windowsChecked = 0;

    // How many pixels to move the window for each step
    // We use 4 - the calibration step can adjust +/- 2 pixels
    // in each direction, which means they will correct for
    // anything which is actually centered in one of the
    // pixels we step over.
    const int step = 4;

    // Create array of scaled images
    std::vector<std::pair<MatT, double> > scaledDepth;
    if (!depthIn.empty())
    {
        MatT depthGpu = MatT(depthIn);
        scalefactor(depthGpu, cv::Size(wsize, wsize), minSize, maxSize, scaleFactor, scaledDepth);
    }
    scalefactor(input, cv::Size(wsize, wsize), minSize, maxSize, scaleFactor, scaledImages);
    // Main loop.  Look at each scaled image in turn
	std::cout << "Scaled images size: " <<  scaledImages.size() << std::endl;
    for (size_t scale = 0; scale < scaledImages.size(); ++scale)
    {
		float depth_multiplier = 0.2;
		float ball_real_size = 247.6; // ball is 9.75in diameter = 247.6 mm
        float percent_image = (float)wsize / scaledImages[scale].first.cols;
		float size_fov = percent_image * hfov_; //TODO fov size
		float depth_avg = (ball_real_size / (2.0 * tan(size_fov / 2.0))) - (4.572 * 25.4);

        float depth_min = depth_avg - depth_avg * depth_multiplier;
        float depth_max = depth_avg + depth_avg * depth_multiplier;
        std::cout << "Target size:" << wsize / scaledImages[scale].second << " Dist:" << depth_avg << " Min/max:" << depth_min << "/" << depth_max << std::endl;

        // Start at the upper left corner.  Loop through the rows and cols until
        // the detection window falls off the edges of the scaled image
        for (int r = 0; (r + wsize) < scaledImages[scale].first.rows; r += step)
        {
            for (int c = 0; (c + wsize) < scaledImages[scale].first.cols; c += step)
            {
				windowsChecked += 1;
                if (!depthIn.empty())
                {
                    cv::Mat detectCheck = cv::Mat(scaledDepth[scale].first(cv::Rect(c, r, wsize, wsize)));
                    if(!depthInRange(depth_min, depth_max, detectCheck))
                    {
                        continue;
                    }
                }
                windows.push_back(Window(cv::Rect(c, r, wsize, wsize), scale));
            }
        }
    }
    std::cout << "generateInitialWindows checked " << windowsChecked << " windows and passed " << windows.size() << std::endl;
}

template<class MatT>
void NNDetect<MatT>::runDetection(CaffeClassifier<MatT>& classifier,
                                  const std::vector<std::pair<MatT, double> >& scaledImages,
                                  const std::vector<Window>& windows,
                                  float threshold,
                                  std::string label,
                                  std::vector<Window>& windowsOut,
                                  std::vector<float>& scores)
{
    windowsOut.clear();
    scores.clear();
    // Accumulate a number of images to test and pass them in to
    // the NN prediction as a batch
    std::vector<MatT> images;

    // Return value from detection. This is a list of indexes from
    // the input which have a high enough confidence score
    std::vector<size_t> detected;

    size_t batchSize = classifier.BatchSize();
    int    counter   = 0;
    double start     = gtod_wrapper(); // grab start time

    // For each input window, grab the correct image
    // subset from the correct scaled image.
    // Detection happens in batches, so save up a list of
    // images and submit them all at once.
    for (auto it = windows.cbegin(); it != windows.cend(); ++it)
    {
        // scaledImages[x].first is a Mat holding the image
        // scaled to the correct size for the given rect.
        // it->second is the index into scaledImages to look at
        // so scaledImages[it->second] is a Mat at the correct
        // scale for the current window. it->first is the
        // rect describing the subset of that image we need to process
        images.push_back(scaledImages[it->second].first(it->first));
        if ((images.size() == batchSize) || ((it + 1) == windows.cend()))
        {
            doBatchPrediction(classifier, images, threshold, label, detected, scores);

            // Clear out images array to start the next batch
            // of processing fresh
            images.clear();

            for (size_t j = 0; j < detected.size(); j++)
            {
                // Indexes in detected array are relative to the start of the
                // current batch just passed in to doBatchPrediction.
                // Use counter to keep track of which batch we're in
                windowsOut.push_back(windows[counter * batchSize + detected[j]]);
            }
            // Keep track of the batch number
            counter++;
        }
    }
    double end = gtod_wrapper();
    std::cout << "runDetection time = " << (end - start) << std::endl;
}

// do 1 run of the classifier. This takes up batch_size predictions
// and adds the index of anything found to the detected list
template<class MatT>
void NNDetect<MatT>::doBatchPrediction(CaffeClassifier<MatT>&   classifier,
                                       const std::vector<MatT>& imgs,
                                       float                    threshold,
                                       const std::string&       label,
                                       std::vector<size_t>&     detected,
                                       std::vector<float>&      scores)
{
    detected.clear();
    // Grab the top 2 detected classes.  Since we're doing an object /
    // not object split, that will get everything
    std::vector<std::vector<Prediction> > predictions = classifier.ClassifyBatch(imgs, 2);

    // Each outer loop is the predictions for one input image
    for (size_t i = 0; i < imgs.size(); ++i)
    {
        // Each inner loop is the prediction for a particular label
        // for the given image, sorted by score.
        //
        // Look for object with label <label>, > threshold confidence
        for (std::vector<Prediction>::const_iterator it = predictions[i].begin(); it != predictions[i].end(); ++it)
        {
            if (it->first == label)
            {
                if (it->second >= threshold)
                {
                    detected.push_back(i);
                    scores.push_back(it->second);
                }
                break;
            }
        }
    }
}

// Be conservative here - if any of the depth values in the target rect
// are in the expected range, consider the rect in range.  Also
// say that it is in range if any of the depth values are negative (i.e. no
// depth info for those pixels)
template <class MatT>
bool NNDetect<MatT>::depthInRange(float depth_min, float depth_max, const cv::Mat &detectCheck)
{
    for (int py = 0; py < detectCheck.rows; py++)
    {
        const float *p = detectCheck.ptr<float>(py);
        for (int px = 0; px < detectCheck.cols; px++)
        {
            if ((p[px] < 0.0) ||((p[px] < depth_max) && (p[px] > depth_min)))
            {
                return true;
            }
        }
    }
    return false;
}

// Explicitly instatiate classes used elsewhere
template class NNDetect<cv::Mat>;
template class NNDetect<cv::gpu::GpuMat>;
<commit_msg>Remove debugging printout<commit_after>#include <iostream>
#include "CaffeBatchPrediction.hpp"
#include "scalefactor.hpp"
#include "fast_nms.hpp"
#include "detect.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/gpu/gpu.hpp>

static double gtod_wrapper(void)
{
    struct timeval tv;

    gettimeofday(&tv, NULL);
    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}

// TODO :: Make a call for GPU Mat input.
// Simple multi-scale detect.  Take a single image, scale it into a number
// of diffent sized images. Run a fixed-size detection window across each
// of them.  Keep track of the scale of each scaled image to map the
// detected rectangles back to the correct location and size on the
// original input images
template<class MatT>
void NNDetect<MatT>::detectMultiscale(const cv::Mat&             inputImg,
                                      const cv::Mat&             depthMat,
                                      const cv::Size&            minSize,
                                      const cv::Size&            maxSize,
                                      double                     scaleFactor,
                                      const std::vector<double>& nmsThreshold,
                                      const std::vector<double>& detectThreshold,
                                      std::vector<cv::Rect>&     rectsOut)
{
    // Size of the first level classifier. Others are an integer multiple
    // of this initial size (2x and maybe 4x if we need it)
    int wsize = d12_.getInputGeometry().width;

    // scaled images which allow us to find images between min and max
    // size for the given classifier input window
    std::vector<std::pair<MatT, double> > scaledImages12;
    std::vector<std::pair<MatT, double> > scaledImages24;
    // Maybe later ? std::vector<std::pair<MatT, double> > scaledImages48;

    // list of windows to work with.
    // A window is a rectangle from a given scaled image along
    // with the index of the scaled image it corresponds with.
    std::vector<Window> windowsIn;
    std::vector<Window> windowsOut;

    // Confidence scores (0.0 - 1.0) for each detected rectangle
    std::vector<float> scores;

    // Generate a list of initial windows to search. Each window will be 12x12 from a scaled image
    // These scaled images let us search for variable sized objects using a fixed-width detector
    MatT f32Img;

    MatT(inputImg).convertTo(f32Img, CV_32FC3);     // classifier runs on float pixel data
    generateInitialWindows(f32Img, depthMat, minSize, maxSize, wsize, scaleFactor, scaledImages12, windowsIn);

    // Generate scaled images for the larger detect sizes as well. Subsequent passes will use larger
    // input sizes. These images will let us grab higher res input as the detector size goes up (as
    // opposed to just scaling up the 12x12 images to a larger size).
    scalefactor(f32Img, cv::Size(wsize * 2, wsize * 2), minSize, maxSize, scaleFactor, scaledImages24);
    // not yet - scalefactor(f32Img, cv::Size(wsize*4,wsize*4), minSize, maxSize, scaleFactor, scaledImages48);

    // Do 1st level of detection. This takes the initial list of windows
    // and returns the list which have a score for "ball" above the
    // threshold listed.
    std::cout << "d12 windows in = " << windowsIn.size() << std::endl;
    runDetection(d12_, scaledImages12, windowsIn, detectThreshold[0], "ball", windowsOut, scores);
    std::cout << "d12 windows out = " << windowsOut.size() << std::endl;
    runNMS(windowsOut, scores, scaledImages12, nmsThreshold[0], windowsIn);
    std::cout << "d12 nms windows out = " << windowsIn.size() << std::endl;

    // Double the size of the rects to get from a 12x12 to 24x24
    // detection window.  Use scaledImages24 for the detection call
    // since that has the scales appropriate for the 24x24 detector
    for (auto it = windowsIn.begin(); it != windowsIn.end(); ++it)
    {
        it->first = cv::Rect(it->first.x * 2, it->first.y * 2,
                             it->first.width * 2, it->first.height * 2);
    }

    if ((detectThreshold.size() > 1) && (detectThreshold[1] > 0.0))
    {
        std::cout << "d24 windows in = " << windowsIn.size() << std::endl;
        runDetection(d24_, scaledImages24, windowsIn, detectThreshold[1], "ball", windowsOut, scores);
        std::cout << "d24 windows out = " << windowsOut.size() << std::endl;
        runNMS(windowsOut, scores, scaledImages24, nmsThreshold[1], windowsIn);
		std::cout << "d24 nms windows out = " << windowsIn.size() << std::endl;
    }

    // Final result - scale the output rectangles back to the
    // correct scale for the original sized image
    rectsOut.clear();
    for (auto it = windowsIn.cbegin(); it != windowsIn.cend(); ++it)
    {
        double   scale = scaledImages24[it->second].second;
        cv::Rect rect(it->first);
        cv::Rect scaledRect(cv::Rect(rect.x / scale, rect.y / scale, rect.width / scale, rect.height / scale));
        rectsOut.push_back(scaledRect);
    }
}

template<class MatT>
void NNDetect<MatT>::runNMS(const std::vector<Window>& windows,
                            const std::vector<float>& scores,
                            const std::vector<std::pair<MatT, double> >& scaledImages,
                            double nmsThreshold,
                            std::vector<Window>& windowsOut)
{
    if ((nmsThreshold > 0.0) && (nmsThreshold < 1.0))
    {
        // Detected is a rect, score pair.
        std::vector<Detected> detected;

        // Need to scale each rect to the correct mapping to the
        // original image, since rectangles from multiple different
        // scales might overlap
        for (size_t i = 0; i < windows.size(); i++)
        {
            double   scale = scaledImages[windows[i].second].second;
            cv::Rect rect(windows[i].first);
            cv::Rect scaledRect(cv::Rect(rect.x / scale, rect.y / scale, rect.width / scale, rect.height / scale));
            detected.push_back(Detected(scaledRect, scores[i]));
        }

        std::vector<size_t> nmsOut;
        fastNMS(detected, nmsThreshold, nmsOut);
        // Each entry of nmsOut is the index of a saved rect/scales
        // pair.  Save the entries from those indexes as the output
        windowsOut.clear();
        for (auto it = nmsOut.cbegin(); it != nmsOut.cend(); ++it)
        {
            windowsOut.push_back(windows[*it]);
        }
    }
    else
    {
        // If not running NMS, output is the same as the input
        windowsOut = windows;
    }
}

template<class MatT>
void NNDetect<MatT>::generateInitialWindows(
    const MatT& input,
    const cv::Mat& depthIn,
    const cv::Size& minSize,
    const cv::Size& maxSize,
    int wsize,
    double scaleFactor,
    std::vector<std::pair<MatT, double> >& scaledImages,
    std::vector<Window>& windows)
{
    windows.clear();
    size_t windowsChecked = 0;

    // How many pixels to move the window for each step
    // We use 4 - the calibration step can adjust +/- 2 pixels
    // in each direction, which means they will correct for
    // anything which is actually centered in one of the
    // pixels we step over.
    const int step = 4;

    // Create array of scaled images
    std::vector<std::pair<MatT, double> > scaledDepth;
    if (!depthIn.empty())
    {
        MatT depthGpu = MatT(depthIn);
        scalefactor(depthGpu, cv::Size(wsize, wsize), minSize, maxSize, scaleFactor, scaledDepth);
    }
    scalefactor(input, cv::Size(wsize, wsize), minSize, maxSize, scaleFactor, scaledImages);
    // Main loop.  Look at each scaled image in turn
	std::cout << "Scaled images size: " <<  scaledImages.size() << std::endl;
    for (size_t scale = 0; scale < scaledImages.size(); ++scale)
    {
		float depth_multiplier = 0.2;
		float ball_real_size = 247.6; // ball is 9.75in diameter = 247.6 mm
        float percent_image = (float)wsize / scaledImages[scale].first.cols;
		float size_fov = percent_image * hfov_; //TODO fov size
		float depth_avg = ball_real_size / (2.0 * tan(size_fov / 2.0));

        float depth_min = depth_avg - depth_avg * depth_multiplier;
        float depth_max = depth_avg + depth_avg * depth_multiplier;
        std::cout << "Target size:" << wsize / scaledImages[scale].second << " Dist:" << depth_avg << " Min/max:" << depth_min << "/" << depth_max << std::endl;

        // Start at the upper left corner.  Loop through the rows and cols until
        // the detection window falls off the edges of the scaled image
        for (int r = 0; (r + wsize) < scaledImages[scale].first.rows; r += step)
        {
            for (int c = 0; (c + wsize) < scaledImages[scale].first.cols; c += step)
            {
				windowsChecked += 1;
                if (!depthIn.empty())
                {
                    cv::Mat detectCheck = cv::Mat(scaledDepth[scale].first(cv::Rect(c, r, wsize, wsize)));
                    if(!depthInRange(depth_min, depth_max, detectCheck))
                    {
                        continue;
                    }
                }
                windows.push_back(Window(cv::Rect(c, r, wsize, wsize), scale));
            }
        }
    }
    std::cout << "generateInitialWindows checked " << windowsChecked << " windows and passed " << windows.size() << std::endl;
}

template<class MatT>
void NNDetect<MatT>::runDetection(CaffeClassifier<MatT>& classifier,
                                  const std::vector<std::pair<MatT, double> >& scaledImages,
                                  const std::vector<Window>& windows,
                                  float threshold,
                                  std::string label,
                                  std::vector<Window>& windowsOut,
                                  std::vector<float>& scores)
{
    windowsOut.clear();
    scores.clear();
    // Accumulate a number of images to test and pass them in to
    // the NN prediction as a batch
    std::vector<MatT> images;

    // Return value from detection. This is a list of indexes from
    // the input which have a high enough confidence score
    std::vector<size_t> detected;

    size_t batchSize = classifier.BatchSize();
    int    counter   = 0;
    double start     = gtod_wrapper(); // grab start time

    // For each input window, grab the correct image
    // subset from the correct scaled image.
    // Detection happens in batches, so save up a list of
    // images and submit them all at once.
    for (auto it = windows.cbegin(); it != windows.cend(); ++it)
    {
        // scaledImages[x].first is a Mat holding the image
        // scaled to the correct size for the given rect.
        // it->second is the index into scaledImages to look at
        // so scaledImages[it->second] is a Mat at the correct
        // scale for the current window. it->first is the
        // rect describing the subset of that image we need to process
        images.push_back(scaledImages[it->second].first(it->first));
        if ((images.size() == batchSize) || ((it + 1) == windows.cend()))
        {
            doBatchPrediction(classifier, images, threshold, label, detected, scores);

            // Clear out images array to start the next batch
            // of processing fresh
            images.clear();

            for (size_t j = 0; j < detected.size(); j++)
            {
                // Indexes in detected array are relative to the start of the
                // current batch just passed in to doBatchPrediction.
                // Use counter to keep track of which batch we're in
                windowsOut.push_back(windows[counter * batchSize + detected[j]]);
            }
            // Keep track of the batch number
            counter++;
        }
    }
    double end = gtod_wrapper();
    std::cout << "runDetection time = " << (end - start) << std::endl;
}

// do 1 run of the classifier. This takes up batch_size predictions
// and adds the index of anything found to the detected list
template<class MatT>
void NNDetect<MatT>::doBatchPrediction(CaffeClassifier<MatT>&   classifier,
                                       const std::vector<MatT>& imgs,
                                       float                    threshold,
                                       const std::string&       label,
                                       std::vector<size_t>&     detected,
                                       std::vector<float>&      scores)
{
    detected.clear();
    // Grab the top 2 detected classes.  Since we're doing an object /
    // not object split, that will get everything
    std::vector<std::vector<Prediction> > predictions = classifier.ClassifyBatch(imgs, 2);

    // Each outer loop is the predictions for one input image
    for (size_t i = 0; i < imgs.size(); ++i)
    {
        // Each inner loop is the prediction for a particular label
        // for the given image, sorted by score.
        //
        // Look for object with label <label>, > threshold confidence
        for (std::vector<Prediction>::const_iterator it = predictions[i].begin(); it != predictions[i].end(); ++it)
        {
            if (it->first == label)
            {
                if (it->second >= threshold)
                {
                    detected.push_back(i);
                    scores.push_back(it->second);
                }
                break;
            }
        }
    }
}

// Be conservative here - if any of the depth values in the target rect
// are in the expected range, consider the rect in range.  Also
// say that it is in range if any of the depth values are negative (i.e. no
// depth info for those pixels)
template <class MatT>
bool NNDetect<MatT>::depthInRange(float depth_min, float depth_max, const cv::Mat &detectCheck)
{
    for (int py = 0; py < detectCheck.rows; py++)
    {
        const float *p = detectCheck.ptr<float>(py);
        for (int px = 0; px < detectCheck.cols; px++)
        {
            if ((p[px] < 0.0) ||((p[px] < depth_max) && (p[px] > depth_min)))
            {
                return true;
            }
        }
    }
    return false;
}

// Explicitly instatiate classes used elsewhere
template class NNDetect<cv::Mat>;
template class NNDetect<cv::gpu::GpuMat>;
<|endoftext|>


<commit_before>// This shows the use of formatting

#include <clue/formatting.hpp>
#include <iostream>
#include <string>
#include <vector>

using namespace clue;
using std::string;

struct User {
    int id;
    string name;
    double score;
};

int main() {
    using fmt::with;

    std::vector<User> users {
        {1, "Alice", 85.0},
        {2, "Bob",   69.2},
        {3, "Nina",  92.5},
        {4, "Mary",  78.3},
        {5, "Mike", 100.0},
        {6, "Tom",   88.6},
        {7, "John",  83.2}
    };

    // width setting
    size_t widths[] = {3, 5, 7};
    size_t row_len = 5;
    for (size_t i = 0; i < 3; ++i) {
        row_len += (widths[i] + 5);
    }
    string sepline(row_len, '-');

    // print header
    std::cout << sepline << std::endl;
    std::cout << str("  |  ",
        with("id",    widths[0], true), "  |  ",
        with("name",  widths[1], true), "  |  ",
        with("score", widths[2], true), "  |  "
    ) << std::endl;
    std::cout << sepline << std::endl;

    // print records
    for (const auto& u: users) {
        std::cout << str("  |  ",
            with(u.id, fmt::dec() | fmt::padzeros, widths[0]), "  |  ",
            with(u.name, widths[1], true), "  |  ",
            with(u.score, fmt::fixed().precision(2), widths[2]), "  |  "
        ) << std::endl;
    }
    std::cout << sepline << std::endl;

    return 0;
}
<commit_msg>add the output of ex_formatting to comments<commit_after>// This shows the use of formatting

#include <clue/formatting.hpp>
#include <iostream>
#include <string>
#include <vector>

using namespace clue;
using std::string;

struct User {
    int id;
    string name;
    double score;
};

int main() {
    using fmt::with;

    std::vector<User> users {
        {1, "Alice", 85.0},
        {2, "Bob",   69.2},
        {3, "Nina",  92.5},
        {4, "Mary",  78.3},
        {5, "Mike", 100.0},
        {6, "Tom",   88.6},
        {7, "John",  83.2}
    };

    // width setting
    size_t widths[] = {3, 5, 7};
    size_t row_len = 5;
    for (size_t i = 0; i < 3; ++i) {
        row_len += (widths[i] + 5);
    }
    string sepline(row_len, '-');

    // print header
    std::cout << sepline << std::endl;
    std::cout << str("  |  ",
        with("id",    widths[0], true), "  |  ",
        with("name",  widths[1], true), "  |  ",
        with("score", widths[2], true), "  |  "
    ) << std::endl;
    std::cout << sepline << std::endl;

    // print records
    for (const auto& u: users) {
        std::cout << str("  |  ",
            with(u.id, fmt::dec() | fmt::padzeros, widths[0]), "  |  ",
            with(u.name, widths[1], true), "  |  ",
            with(u.score, fmt::fixed().precision(2), widths[2]), "  |  "
        ) << std::endl;
    }
    std::cout << sepline << std::endl;

    // The codes above shows the following table to the console:
    //
    // -----------------------------------
    //   |  id   |  name   |  score    |
    // -----------------------------------
    //   |  001  |  Alice  |    85.00  |
    //   |  002  |  Bob    |    69.20  |
    //   |  003  |  Nina   |    92.50  |
    //   |  004  |  Mary   |    78.30  |
    //   |  005  |  Mike   |   100.00  |
    //   |  006  |  Tom    |    88.60  |
    //   |  007  |  John   |    83.20  |
    // -----------------------------------
    //

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <bitset>
#include <ctime>
#include <limits>
#include <boost/spirit/include/karma.hpp>

#define TIMEDIFF(start, stop) 1000.0 * (stop - start)/CLOCKS_PER_SEC

template <int MaxNumber>
class ErasthostenesSieve
{
   std::bitset<MaxNumber> listOfNaturals;
   std::ofstream output;
   int counter;

   public:
   ErasthostenesSieve() :
           output("primesEveryWhere.txt", std::ios::out | std::ios::trunc),
           counter(0)
   {
      listOfNaturals.set();
      listOfNaturals.set(0, false); // 1 is not prime
   }

   ~ErasthostenesSieve()
   {
      output.close();
   }

   int applyTheSieve()
   {
      int base = 2;
      print( base );

      for (base = 3; base * base < MaxNumber; base += 2 )
      {
         if (not listOfNaturals[base - 1])
            continue;

         print( base );

         for (int pivot = base + base ; pivot <= MaxNumber; pivot += base)
         {
            listOfNaturals.set(pivot - 1, false);
         }
      }

      for (; base <= MaxNumber; base += 2)
      {
         if (listOfNaturals[base - 1])
            print( base );
      }
      return counter;
   }

   private:
   void print(int number)
   {
      char buffer[16];
      char* x = buffer;
      boost::spirit::karma::generate(x, boost::spirit::int_, number);
      output << buffer << "\n";
      counter ++;
   }
};

int main(int argc, char ** argv)
{
   const int MaxNumber = 32452843;
   clock_t t1, t2;

   t1 = std::clock();

   ErasthostenesSieve<MaxNumber> siever;
   int printedPrimes = siever.applyTheSieve();

   t2 = std::clock();

   // Summary
   std::cout.precision(std::numeric_limits<double>::digits10);
   std::cerr << "Used " << std::fixed << TIMEDIFF(t1, t2)
             << " msecs to calculate " << printedPrimes
             << " primes." << std::endl;
}
<commit_msg>Using a simple memory buffer, before printing.<commit_after>#include <iostream>
#include <fstream>
#include <bitset>
#include <ctime>
#include <limits>
#include <boost/spirit/include/karma.hpp>

#define TIMEDIFF(start, stop) 1000.0 * (stop - start)/CLOCKS_PER_SEC
#define BUFFER_SIZE 512

template <int MaxNumber>
class ErasthostenesSieve
{
   std::bitset<MaxNumber> listOfNaturals;
   std::ofstream output;
   int counter;
   char buffer[BUFFER_SIZE];
   char * p_input;

   public:
   ErasthostenesSieve() :
           output("primesEveryWhere.txt", std::ios::out | std::ios::trunc),
           counter(0),
           p_input(buffer)
   {
      listOfNaturals.set();
      listOfNaturals.set(0, false); // 1 is not prime
   }

   ~ErasthostenesSieve()
   {
      if (p_input != buffer)
         output << buffer; //flush
      output.close();
   }

   int applyTheSieve()
   {
      int base = 2;
      print( base );

      for (base = 3; base * base < MaxNumber; base += 2 )
      {
         if (not listOfNaturals[base - 1])
            continue;

         print( base );

         for (int pivot = base + base ; pivot <= MaxNumber; pivot += base)
         {
            listOfNaturals.set(pivot - 1, false);
         }
      }

      for (; base <= MaxNumber; base += 2)
      {
         if (listOfNaturals[base - 1])
            print( base );
      }
      return counter;
   }

   private:
   inline void print(int number)
   {
//      char buffer[16];
//      char* x = buffer;
//      boost::spirit::karma::generate(x, boost::spirit::int_, number);
//      output << buffer << "\n";
      doPrint(number);
      counter ++;
   }

   inline void doPrint(int number)
   {
      boost::spirit::karma::generate(p_input, boost::spirit::int_, number);
      *p_input++ = '\n';
      if (p_input - buffer > BUFFER_SIZE - 16)
      {
         output << buffer;
         p_input = buffer;
         memset(buffer, 0u, BUFFER_SIZE);
      }
   }
};

int main(int argc, char ** argv)
{
   const int MaxNumber = 32452843;
   clock_t t1, t2;

   t1 = std::clock();

   ErasthostenesSieve<MaxNumber> siever;
   int printedPrimes = siever.applyTheSieve();

   t2 = std::clock();

   // Summary
   std::cout.precision(std::numeric_limits<double>::digits10);
   std::cerr << "Used " << std::fixed << TIMEDIFF(t1, t2)
             << " msecs to calculate " << printedPrimes
             << " primes." << std::endl;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Adam Chyła, adam@chyla.org
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "knn_analyzer_object.h"

#include <boost/log/trivial.hpp>
#include <cmath>
#include <limits>

#include "system.h"

using namespace ::apache::database::detail;
using namespace ::apache::type;
using namespace ::database::type;
using namespace ::type;

namespace apache
{

namespace analyzer
{

namespace detail
{

KnnAnalyzerObjectPtr KnnAnalyzerObject::Create(::database::detail::GeneralDatabaseFunctionsInterfacePtr general_database_functions,
                                               ::apache::database::DatabaseFunctionsPtr apache_database_functions) {
  auto system = System::Create();

  return Create(system, general_database_functions, apache_database_functions);
}

KnnAnalyzerObjectPtr KnnAnalyzerObject::Create(detail::SystemInterfacePtr system_interface,
                                               ::database::detail::GeneralDatabaseFunctionsInterfacePtr general_database_functions,
                                               ::apache::database::DatabaseFunctionsPtr apache_database_functions) {
  return KnnAnalyzerObjectPtr(new KnnAnalyzerObject(system_interface, general_database_functions, apache_database_functions));
}

void KnnAnalyzerObject::Analyze() {
  auto now = GetCurrentTimestamp();
  auto last_analyze = GetLastAnalyzeTimestamp(now);

  for (auto agent_name : general_database_functions_->GetAgentNames()) {
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::Analyze: Preparing agent: " << agent_name;

    for (auto virtualhost_name : apache_database_functions_->GetVirtualhostNames(agent_name)) {
      BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::Analyze: Preparing virtualhost: " << virtualhost_name;

      // sprawdzic istnienie konfiguracji
      AnalyzeVirtualhost(agent_name, virtualhost_name, last_analyze, now);
    }
  }

  apache_database_functions_->SetLastRun(LastRunType::ANALYZING, now);
}

void KnnAnalyzerObject::AnalyzeVirtualhost(const ::database::type::AgentName &agent_name,
                                           const ::database::type::VirtualhostName &virtualhost_name,
                                           const ::type::Timestamp &last_analyze_timestamp,
                                           const ::type::Timestamp &now) {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeVirtualhost: Function call";
  constexpr RowsCount MAX_ROWS_IN_MEMORY = 100;
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Max rows in memory: " << MAX_ROWS_IN_MEMORY;
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Last analyze timestamp: " << last_analyze_timestamp;
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Current timestamp: " << now;

  auto agent_id = general_database_functions_->GetAgentNameId(agent_name);
  auto virtualhost_id = apache_database_functions_->GetVirtualhostNameId(virtualhost_name);

  auto from = last_analyze_timestamp;
  auto count = apache_database_functions_->GetLearningSessionsCount(agent_id, virtualhost_id);
  for (auto session_id : apache_database_functions_->GetLearningSessionsIds(agent_id, virtualhost_id, count, 0))
  {
    auto session = apache_database_functions_->GetOneSessionStatistic(session_id);
    if (from < session.session_start)
      from = session.session_start;
  }
  from = ::Timestamp::Create(from.GetTime() + 1, from.GetDate());
  auto to = now;

  auto sessions_count = apache_database_functions_->GetSessionStatisticsCount(agent_name, virtualhost_name, from, to);
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeVirtualhost: Found " << sessions_count << " sessions to analyze";

  for (RowsCount i = 0; i < sessions_count / MAX_ROWS_IN_MEMORY; ++i)
    AnalyzeSessions(agent_name, virtualhost_name, from, to, MAX_ROWS_IN_MEMORY, i);

  auto left_offset = sessions_count - (sessions_count % MAX_ROWS_IN_MEMORY);
  auto left_logs_count = sessions_count % MAX_ROWS_IN_MEMORY;

  AnalyzeSessions(agent_name, virtualhost_name, from, to, left_logs_count, left_offset);
}

void KnnAnalyzerObject::AnalyzeSessions(const ::database::type::AgentName &agent_name,
                                        const ::database::type::VirtualhostName &virtualhost_name,
                                        const ::type::Timestamp &from,
                                        const ::type::Timestamp &to,
                                        unsigned limit,
                                        ::database::type::RowsCount offset) {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Function call";
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Analyzing sessions: " << agent_name << "/" << virtualhost_name << " from " << from << " to " << to << " (limit=" << limit << "; offset=" << offset << ")";
  constexpr RowsCount MAX_ROWS_IN_MEMORY = 100;

  auto sessions_part = apache_database_functions_->GetSessionStatistics(agent_name, virtualhost_name,
                                                                        from, to,
                                                                        limit, offset);
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Received " << sessions_part.size() << " sessions statictics";

  auto agent_id = general_database_functions_->GetAgentNameId(agent_name);
  auto virtualhost_id = apache_database_functions_->GetVirtualhostNameId(virtualhost_name);
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Agent ID: " << agent_id;
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Virtualhost ID " << virtualhost_id;

  auto learning_set_count = apache_database_functions_->GetLearningSessionsCount(agent_id, virtualhost_id);
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Found " << learning_set_count << " sessions in learning set";

  for (auto session : sessions_part) {
    for (auto dsi : distance_table_) {
      dsi.first = 0;
      dsi.second = -1;
    }

    for (RowsCount i = 0; i < learning_set_count / MAX_ROWS_IN_MEMORY; ++i)
      AnalyzeSessionsWithLearningSet(agent_id, virtualhost_id, MAX_ROWS_IN_MEMORY, i, session);

    auto left_offset = learning_set_count - (learning_set_count % MAX_ROWS_IN_MEMORY);
    auto left_logs_count = learning_set_count % MAX_ROWS_IN_MEMORY;

    AnalyzeSessionsWithLearningSet(agent_id, virtualhost_id, left_logs_count, left_offset, session);

    session.is_anomaly =
        (distance_table_.at(0).first +
        distance_table_.at(1).first +
        distance_table_.at(2).first) > 1;
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Is session with id " << session.id << " anomaly? - " << session.is_anomaly;
  }
}

void KnnAnalyzerObject::AnalyzeSessionsWithLearningSet(const ::database::type::RowId &agent_name_id,
                                                       const ::database::type::RowId &virtualhost_name_id,
                                                       unsigned limit,
                                                       ::database::type::RowsCount offset,
                                                       const ::apache::type::ApacheSessionEntry &session_to_analyze) {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessionsWithLearningSet: Function call";
  auto learning_set_ids = apache_database_functions_->GetLearningSessionsIds(agent_name_id, virtualhost_name_id, limit, offset);

  for (auto session_id : learning_set_ids) {
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessionsWithLearningSet: Comparing session to analyze with id=" << session_to_analyze.id << " to session from learning set " << session_id;

    double d = Distance(session_to_analyze,
                        apache_database_functions_->GetOneSessionStatistic(session_id));

    for (auto dsi : distance_table_) {
      if (dsi.first < d || dsi.second == -1) {
        BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessionsWithLearningSet: Updating distance table";

        dsi.first = d;
        dsi.second = session_id;
        break;
      }
    }

    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessionsWithLearningSet: New distance table: "
        << "(" << distance_table_.at(0).first << "; " << distance_table_.at(0).second << "), "
        << "(" << distance_table_.at(1).first << "; " << distance_table_.at(1).second << "), "
        << "(" << distance_table_.at(2).first << "; " << distance_table_.at(2).second << "), ";
  }
}

double KnnAnalyzerObject::Distance(const ::apache::type::ApacheSessionEntry &a,
                                   const ::apache::type::ApacheSessionEntry &b) const {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::Distance: Function call";

  double d = sqrt(pow(a.session_length - b.session_length, 2) +
                  pow(a.bandwidth_usage - b.bandwidth_usage, 2) +
                  pow(a.requests_count - b.requests_count, 2) +
                  pow(a.error_percentage - b.error_percentage, 2)
                  );

  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::Distance: Distance between session id=" << a.id << "; id2=" << b.id << " is " << d;

  return d;
}

KnnAnalyzerObject::KnnAnalyzerObject(detail::SystemInterfacePtr system_interface,
                                     ::database::detail::GeneralDatabaseFunctionsInterfacePtr general_database_functions,
                                     ::apache::database::DatabaseFunctionsPtr apache_database_functions) :
system_interface_(system_interface),
general_database_functions_(general_database_functions),
apache_database_functions_(apache_database_functions) {
}

Timestamp KnnAnalyzerObject::GetCurrentTimestamp() const {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::GetCurrentTimestamp: Function call";
  time_t t = system_interface_->Time(nullptr);
  struct tm *now = system_interface_->LocalTime(&t);

  return Timestamp::Create(Time::Create(now->tm_hour, now->tm_min, now->tm_sec),
                           Date::Create(now->tm_mday, now->tm_mon + 1, now->tm_year + 1900));
}

::type::Timestamp KnnAnalyzerObject::GetLastAnalyzeTimestamp(const ::type::Timestamp &now) const {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::GetLastAnalyzeTimestamp: Function call";
  Timestamp last_analyze;

  auto is_stats = apache_database_functions_->IsLastRunSet(LastRunType::ANALYZING);
  if (is_stats) {
    last_analyze = apache_database_functions_->GetLastRun(LastRunType::ANALYZING);
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::GetLastAnalyzeTimestamp: Found last analyze time " << last_analyze;
  }
  else {
    last_analyze.Set(0, 0, 0, 1, 1, 2016);
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::GetLastAnalyzeTimestamp: Last analyze time not found - assuming " << last_analyze;
  }

  return last_analyze;
}

}

}

}
<commit_msg>Change range for to simple for<commit_after>/*
 * Copyright 2016 Adam Chyła, adam@chyla.org
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "knn_analyzer_object.h"

#include <boost/log/trivial.hpp>
#include <cmath>
#include <limits>

#include "system.h"

using namespace ::apache::database::detail;
using namespace ::apache::type;
using namespace ::database::type;
using namespace ::type;

namespace apache
{

namespace analyzer
{

namespace detail
{

KnnAnalyzerObjectPtr KnnAnalyzerObject::Create(::database::detail::GeneralDatabaseFunctionsInterfacePtr general_database_functions,
                                               ::apache::database::DatabaseFunctionsPtr apache_database_functions) {
  auto system = System::Create();

  return Create(system, general_database_functions, apache_database_functions);
}

KnnAnalyzerObjectPtr KnnAnalyzerObject::Create(detail::SystemInterfacePtr system_interface,
                                               ::database::detail::GeneralDatabaseFunctionsInterfacePtr general_database_functions,
                                               ::apache::database::DatabaseFunctionsPtr apache_database_functions) {
  return KnnAnalyzerObjectPtr(new KnnAnalyzerObject(system_interface, general_database_functions, apache_database_functions));
}

void KnnAnalyzerObject::Analyze() {
  auto now = GetCurrentTimestamp();
  auto last_analyze = GetLastAnalyzeTimestamp(now);

  for (auto agent_name : general_database_functions_->GetAgentNames()) {
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::Analyze: Preparing agent: " << agent_name;

    for (auto virtualhost_name : apache_database_functions_->GetVirtualhostNames(agent_name)) {
      BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::Analyze: Preparing virtualhost: " << virtualhost_name;

      // sprawdzic istnienie konfiguracji
      AnalyzeVirtualhost(agent_name, virtualhost_name, last_analyze, now);
    }
  }

  apache_database_functions_->SetLastRun(LastRunType::ANALYZING, now);
}

void KnnAnalyzerObject::AnalyzeVirtualhost(const ::database::type::AgentName &agent_name,
                                           const ::database::type::VirtualhostName &virtualhost_name,
                                           const ::type::Timestamp &last_analyze_timestamp,
                                           const ::type::Timestamp &now) {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeVirtualhost: Function call";
  constexpr RowsCount MAX_ROWS_IN_MEMORY = 100;
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Max rows in memory: " << MAX_ROWS_IN_MEMORY;
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Last analyze timestamp: " << last_analyze_timestamp;
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Current timestamp: " << now;

  auto agent_id = general_database_functions_->GetAgentNameId(agent_name);
  auto virtualhost_id = apache_database_functions_->GetVirtualhostNameId(virtualhost_name);

  auto from = last_analyze_timestamp;
  auto count = apache_database_functions_->GetLearningSessionsCount(agent_id, virtualhost_id);
  for (auto session_id : apache_database_functions_->GetLearningSessionsIds(agent_id, virtualhost_id, count, 0))
  {
    auto session = apache_database_functions_->GetOneSessionStatistic(session_id);
    if (from < session.session_start)
      from = session.session_start;
  }
  from = ::Timestamp::Create(from.GetTime() + 1, from.GetDate());
  auto to = now;

  auto sessions_count = apache_database_functions_->GetSessionStatisticsCount(agent_name, virtualhost_name, from, to);
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeVirtualhost: Found " << sessions_count << " sessions to analyze";

  for (RowsCount i = 0; i < sessions_count / MAX_ROWS_IN_MEMORY; ++i)
    AnalyzeSessions(agent_name, virtualhost_name, from, to, MAX_ROWS_IN_MEMORY, i);

  auto left_offset = sessions_count - (sessions_count % MAX_ROWS_IN_MEMORY);
  auto left_logs_count = sessions_count % MAX_ROWS_IN_MEMORY;

  AnalyzeSessions(agent_name, virtualhost_name, from, to, left_logs_count, left_offset);
}

void KnnAnalyzerObject::AnalyzeSessions(const ::database::type::AgentName &agent_name,
                                        const ::database::type::VirtualhostName &virtualhost_name,
                                        const ::type::Timestamp &from,
                                        const ::type::Timestamp &to,
                                        unsigned limit,
                                        ::database::type::RowsCount offset) {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Function call";
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Analyzing sessions: " << agent_name << "/" << virtualhost_name << " from " << from << " to " << to << " (limit=" << limit << "; offset=" << offset << ")";
  constexpr RowsCount MAX_ROWS_IN_MEMORY = 100;

  auto sessions_part = apache_database_functions_->GetSessionStatistics(agent_name, virtualhost_name,
                                                                        from, to,
                                                                        limit, offset);
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Received " << sessions_part.size() << " sessions statictics";

  auto agent_id = general_database_functions_->GetAgentNameId(agent_name);
  auto virtualhost_id = apache_database_functions_->GetVirtualhostNameId(virtualhost_name);
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Agent ID: " << agent_id;
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Virtualhost ID " << virtualhost_id;

  auto learning_set_count = apache_database_functions_->GetLearningSessionsCount(agent_id, virtualhost_id);
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Found " << learning_set_count << " sessions in learning set";

  for (auto session : sessions_part) {
    for (auto i = 0; i < distance_table_.size(); ++i) {
      distance_table_[i].first = 0;
      distance_table_[i].second = -1;
    }

    for (RowsCount i = 0; i < learning_set_count / MAX_ROWS_IN_MEMORY; ++i)
      AnalyzeSessionsWithLearningSet(agent_id, virtualhost_id, MAX_ROWS_IN_MEMORY, i, session);

    auto left_offset = learning_set_count - (learning_set_count % MAX_ROWS_IN_MEMORY);
    auto left_logs_count = learning_set_count % MAX_ROWS_IN_MEMORY;

    AnalyzeSessionsWithLearningSet(agent_id, virtualhost_id, left_logs_count, left_offset, session);

    session.is_anomaly =
        (distance_table_.at(0).first +
        distance_table_.at(1).first +
        distance_table_.at(2).first) > 1;
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessions: Is session with id " << session.id << " anomaly? - " << session.is_anomaly;
  }
}

void KnnAnalyzerObject::AnalyzeSessionsWithLearningSet(const ::database::type::RowId &agent_name_id,
                                                       const ::database::type::RowId &virtualhost_name_id,
                                                       unsigned limit,
                                                       ::database::type::RowsCount offset,
                                                       const ::apache::type::ApacheSessionEntry &session_to_analyze) {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessionsWithLearningSet: Function call";
  auto learning_set_ids = apache_database_functions_->GetLearningSessionsIds(agent_name_id, virtualhost_name_id, limit, offset);

  for (auto session_id : learning_set_ids) {
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessionsWithLearningSet: Comparing session to analyze with id=" << session_to_analyze.id << " to session from learning set " << session_id;

    double d = Distance(session_to_analyze,
                        apache_database_functions_->GetOneSessionStatistic(session_id));

    for (auto dsi : distance_table_) {
      if (dsi.first < d || dsi.second == -1) {
        BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessionsWithLearningSet: Updating distance table";

        dsi.first = d;
        dsi.second = session_id;
        break;
      }
    }

    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::AnalyzeSessionsWithLearningSet: New distance table: "
        << "(" << distance_table_.at(0).first << "; " << distance_table_.at(0).second << "), "
        << "(" << distance_table_.at(1).first << "; " << distance_table_.at(1).second << "), "
        << "(" << distance_table_.at(2).first << "; " << distance_table_.at(2).second << "), ";
  }
}

double KnnAnalyzerObject::Distance(const ::apache::type::ApacheSessionEntry &a,
                                   const ::apache::type::ApacheSessionEntry &b) const {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::Distance: Function call";

  double d = sqrt(pow(a.session_length - b.session_length, 2) +
                  pow(a.bandwidth_usage - b.bandwidth_usage, 2) +
                  pow(a.requests_count - b.requests_count, 2) +
                  pow(a.error_percentage - b.error_percentage, 2)
                  );

  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::Distance: Distance between session id=" << a.id << "; id2=" << b.id << " is " << d;

  return d;
}

KnnAnalyzerObject::KnnAnalyzerObject(detail::SystemInterfacePtr system_interface,
                                     ::database::detail::GeneralDatabaseFunctionsInterfacePtr general_database_functions,
                                     ::apache::database::DatabaseFunctionsPtr apache_database_functions) :
system_interface_(system_interface),
general_database_functions_(general_database_functions),
apache_database_functions_(apache_database_functions) {
}

Timestamp KnnAnalyzerObject::GetCurrentTimestamp() const {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::GetCurrentTimestamp: Function call";
  time_t t = system_interface_->Time(nullptr);
  struct tm *now = system_interface_->LocalTime(&t);

  return Timestamp::Create(Time::Create(now->tm_hour, now->tm_min, now->tm_sec),
                           Date::Create(now->tm_mday, now->tm_mon + 1, now->tm_year + 1900));
}

::type::Timestamp KnnAnalyzerObject::GetLastAnalyzeTimestamp(const ::type::Timestamp &now) const {
  BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::GetLastAnalyzeTimestamp: Function call";
  Timestamp last_analyze;

  auto is_stats = apache_database_functions_->IsLastRunSet(LastRunType::ANALYZING);
  if (is_stats) {
    last_analyze = apache_database_functions_->GetLastRun(LastRunType::ANALYZING);
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::GetLastAnalyzeTimestamp: Found last analyze time " << last_analyze;
  }
  else {
    last_analyze.Set(0, 0, 0, 1, 1, 2016);
    BOOST_LOG_TRIVIAL(debug) << "apache::analyzer::detail::KnnAnalyzerObject::GetLastAnalyzeTimestamp: Last analyze time not found - assuming " << last_analyze;
  }

  return last_analyze;
}

}

}

}
<|endoftext|>


<commit_before>#undef UNICODE
#undef _UNICODE

#pragma once

#ifdef _MSC_VER
#pragma warning(push, 1) /* disable warnings within system headers */
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <msiquery.h>
#include <imagehlp.h>
#include <tchar.h>
#include <strsafe.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <malloc.h>
#include <time.h>
#include <string>

const DWORD PE_Signature = 0x00004550;

#ifdef DEBUG
inline void OutputDebugStringFormat( LPCSTR pFormat, ... )
{
    CHAR    buffer[1024];
    va_list args;

    va_start( args, pFormat );
    StringCchVPrintfA( buffer, sizeof(buffer), pFormat, args );
    OutputDebugStringA( buffer );
}
#else
static inline void OutputDebugStringFormat( LPCSTR, ... )
{
}
#endif

static bool IsValidHandle( HANDLE handle )
{
    return NULL != handle && INVALID_HANDLE_VALUE != handle;
}

static std::string GetMsiProperty(MSIHANDLE handle, const std::string& sProperty)
{
    std::string result;
    TCHAR       szDummy[1] = TEXT("");
    DWORD       nChars = 0;

    if (MsiGetProperty(handle, sProperty.c_str(), szDummy, &nChars) == ERROR_MORE_DATA)
    {
        DWORD nBytes = ++nChars * sizeof(TCHAR);
        LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
        ZeroMemory( buffer, nBytes );
        MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
        result = buffer;
    }
    return result;
}

static BOOL rebaseImage( const std::string& filePath, LPVOID address )
{
    ULONG ulOldImageSize;
    ULONG_PTR lpOldImageBase;
    ULONG ulNewImageSize;
    ULONG_PTR lpNewImageBase = reinterpret_cast<ULONG_PTR>(address);

    BOOL bResult = ReBaseImage(
        filePath.c_str(),
        "",
        TRUE,
        FALSE,
        FALSE,
        0,
        &ulOldImageSize,
        &lpOldImageBase,
        &ulNewImageSize,
        &lpNewImageBase,
        (ULONG)time(NULL) );

    return bResult;
}

static BOOL rebaseImage( MSIHANDLE /*handle*/, const std::string& sFilePath, LPVOID address )
{
    std::string mystr;
    mystr = "Full file: " + sFilePath;

    BOOL bResult = rebaseImage( sFilePath, address );

    if ( !bResult )
    {
        OutputDebugStringFormat( "Rebasing library %s failed", mystr.c_str() );
    }

    return bResult;
}

static BOOL rebaseImagesInFolder( MSIHANDLE handle, const std::string& sPath, LPVOID address )
{
    std::string   sDir     = sPath;
    std::string   sPattern = sPath + TEXT("*.dll");

    WIN32_FIND_DATA aFindFileData;
    HANDLE  hFind = FindFirstFile( sPattern.c_str(), &aFindFileData );

    if ( IsValidHandle(hFind) )
    {
        BOOL fSuccess = false;

        do
        {
            std::string sLibFile = sDir + aFindFileData.cFileName;
            rebaseImage( handle, sLibFile, address );
            fSuccess = FindNextFile( hFind, &aFindFileData );
        }
        while ( fSuccess );

        FindClose( hFind );
    }

    return ERROR_SUCCESS;
}

static BOOL rebaseImages( MSIHANDLE handle, LPVOID pAddress )
{
    std::string sInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION"));

    std::string sBasisDir  = sInstallPath + TEXT("Basis\\program\\");
    std::string sOfficeDir = sInstallPath + TEXT("program\\");
    std::string sUreDir    = sInstallPath + TEXT("URE\\bin\\");

    BOOL bResult = rebaseImagesInFolder( handle, sBasisDir, pAddress );
    bResult &= rebaseImagesInFolder( handle, sOfficeDir, pAddress );
    bResult &= rebaseImagesInFolder( handle, sUreDir, pAddress );

    return bResult;
}

static BOOL IsServerSystem( MSIHANDLE /*handle*/ )
{
    OSVERSIONINFOEX osVersionInfoEx;
    osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osVersionInfoEx));

    if ( osVersionInfoEx.wProductType != VER_NT_WORKSTATION )
        return TRUE;
    else
        return FALSE;
}

extern "C" BOOL __stdcall RebaseLibrariesOnProperties( MSIHANDLE handle )
{
    static LPVOID pDefault = reinterpret_cast<LPVOID>(0x10000000);

    std::string sDontOptimizeLibs = GetMsiProperty(handle, TEXT("DONTOPTIMIZELIBS"));
    if ( sDontOptimizeLibs.length() > 0 && sDontOptimizeLibs == "1" )
        return TRUE;

    if ( !IsServerSystem( handle ))
        return rebaseImages( handle, pDefault );

    return TRUE;
}
<commit_msg>CWS-TOOLING: integrate CWS native367<commit_after>#undef UNICODE
#undef _UNICODE

#pragma once

#ifdef _MSC_VER
#pragma warning(push, 1) /* disable warnings within system headers */
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <msiquery.h>
#include <imagehlp.h>
#include <tchar.h>
#include <strsafe.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <malloc.h>
#include <time.h>
#include <string>
#include <hash_map>

const DWORD PE_Signature = 0x00004550;
typedef std::pair< std::string, bool > StringPair;
typedef std::hash_map< std::string, bool > ExcludeLibsMap;

#ifdef DEBUG
static void OutputDebugStringFormat( LPCSTR pFormat, ... )
{
    CHAR    buffer[1024];
    va_list args;

    va_start( args, pFormat );
    StringCchVPrintfA( buffer, sizeof(buffer), pFormat, args );
    OutputDebugStringA( buffer );
}
#else
static void OutputDebugStringFormat( LPCSTR, ... )
{
}
#endif

static bool IsValidHandle( HANDLE handle )
{
    return NULL != handle && INVALID_HANDLE_VALUE != handle;
}

static std::string GetMsiProperty(MSIHANDLE handle, const std::string& sProperty)
{
    std::string result;
    TCHAR       szDummy[1] = TEXT("");
    DWORD       nChars = 0;

    if (MsiGetProperty(handle, sProperty.c_str(), szDummy, &nChars) == ERROR_MORE_DATA)
    {
        DWORD nBytes = ++nChars * sizeof(TCHAR);
        LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
        ZeroMemory( buffer, nBytes );
        MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
        result = buffer;
    }
    return result;
}

static BOOL rebaseImage( const std::string& filePath, LPVOID address )
{
    ULONG ulOldImageSize;
    ULONG_PTR lpOldImageBase;
    ULONG ulNewImageSize;
    ULONG_PTR lpNewImageBase = reinterpret_cast<ULONG_PTR>(address);

    BOOL bResult = ReBaseImage(
        filePath.c_str(),
        "",
        TRUE,
        FALSE,
        FALSE,
        0,
        &ulOldImageSize,
        &lpOldImageBase,
        &ulNewImageSize,
        &lpNewImageBase,
        (ULONG)time(NULL) );

    return bResult;
}

static BOOL rebaseImage( MSIHANDLE /*handle*/, const std::string& sFilePath, LPVOID address )
{
    std::string mystr;
    mystr = "Full file: " + sFilePath;

    BOOL bResult = rebaseImage( sFilePath, address );

    if ( !bResult )
    {
        OutputDebugStringFormat( "Rebasing library %s failed", mystr.c_str() );
    }

    return bResult;
}

static BOOL rebaseImagesInFolder( MSIHANDLE handle, const std::string& sPath, LPVOID address, ExcludeLibsMap& rExcludeMap )
{
    std::string     sDir     = sPath;
    std::string     sPattern = sPath + TEXT("*.dll");
    WIN32_FIND_DATA aFindFileData;

    HANDLE hFind = FindFirstFile( sPattern.c_str(), &aFindFileData );
    if ( IsValidHandle(hFind) )
    {
        BOOL fSuccess = false;

        do
        {
            std::string sFileName = aFindFileData.cFileName;
            if ( rExcludeMap.find( sFileName ) == rExcludeMap.end() )
            {
                OutputDebugStringFormat( "Rebase library: %s", sFileName.c_str() );
                std::string sLibFile = sDir +  sFileName;
                rebaseImage( handle, sLibFile, address );
            }
            else
            {
                OutputDebugStringFormat( "Exclude library %s from rebase", sFileName.c_str() );
            }

            fSuccess = FindNextFile( hFind, &aFindFileData );
        }
        while ( fSuccess );

        FindClose( hFind );
    }

    return ERROR_SUCCESS;
}

static BOOL rebaseImages( MSIHANDLE handle, LPVOID pAddress, ExcludeLibsMap& rMap )
{
    std::string sInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION"));

    std::string sBasisDir  = sInstallPath + TEXT("Basis\\program\\");
    std::string sOfficeDir = sInstallPath + TEXT("program\\");
    std::string sUreDir    = sInstallPath + TEXT("URE\\bin\\");

    BOOL bResult = rebaseImagesInFolder( handle, sBasisDir, pAddress, rMap );
    bResult &= rebaseImagesInFolder( handle, sOfficeDir, pAddress, rMap );
    bResult &= rebaseImagesInFolder( handle, sUreDir, pAddress, rMap );

    return bResult;
}

static BOOL IsServerSystem( MSIHANDLE /*handle*/ )
{
    OSVERSIONINFOEX osVersionInfoEx;
    osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osVersionInfoEx));

    if ( osVersionInfoEx.wProductType != VER_NT_WORKSTATION )
    {
        OutputDebugStringFormat( "Server system detected. No rebase necessary!" );
        return TRUE;
    }
    else
    {
        OutputDebugStringFormat( "Client system detected. Rebase necessary!" );
        return FALSE;
    }
}

static void InitExcludeFromRebaseList( MSIHANDLE handle, ExcludeLibsMap& rMap )
{
    size_t      nPos( 0 );
    const TCHAR cDelim = ',';
    std::string sLibsExcluded = GetMsiProperty(handle, TEXT("EXCLUDE_FROM_REBASE"));

    while ( nPos < sLibsExcluded.size() )
    {
        size_t nDelPos = sLibsExcluded.find_first_of( cDelim, nPos );

        std::string sExcludedLibName;
        if ( nDelPos != std::string::npos )
        {
            sExcludedLibName = sLibsExcluded.substr( nPos, nDelPos - nPos );
            nPos = nDelPos+1;
        }
        else
        {
            sExcludedLibName = sLibsExcluded.substr( nPos );
            nPos = sLibsExcluded.size();
        }

        if ( sExcludedLibName.size() > 0 )
        {
            OutputDebugStringFormat( "Insert library %s into exclude from rebase list", sExcludedLibName.c_str() );
            rMap.insert( StringPair( sExcludedLibName, true ));
        }
    }
}

extern "C" BOOL __stdcall RebaseLibrariesOnProperties( MSIHANDLE handle )
{
    static LPVOID pDefault = reinterpret_cast<LPVOID>(0x10000000);

    OutputDebugStringFormat( "RebaseLibrariesOnProperties has been called" );
    std::string sDontOptimizeLibs = GetMsiProperty(handle, TEXT("DONTOPTIMIZELIBS"));
    if ( sDontOptimizeLibs.length() > 0 && sDontOptimizeLibs == "1" )
    {
        OutputDebugStringFormat( "Don't optimize libraries set. No rebase necessary!" );
        return TRUE;
    }

    if ( !IsServerSystem( handle ))
    {
        ExcludeLibsMap aExcludeLibsMap;
        InitExcludeFromRebaseList( handle, aExcludeLibsMap );

        return rebaseImages( handle, pDefault, aExcludeLibsMap );
    }

    return TRUE;
}
<|endoftext|>