<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Persistent string storage, and translation of hardcoded strings.
  */

#include "thcrap.h"
#include <unordered_map>

/// Detour chains
/// -------------
W32U8_DETOUR_CHAIN_DEF(MessageBox);
/// -------------

// Length-prefixed string object used for persistent storage
typedef struct {
	size_t len;
	char str;
} storage_string_t;

static json_t *strings_storage = NULL;

SRWLOCK stringlocs_srwlock = {SRWLOCK_INIT};
std::unordered_map<const char *, const char *> stringlocs;

#define addr_key_len 2 + (sizeof(void*) * 2) + 1

void stringlocs_reparse(void)
{
	// Since we can't use the jsondata module to make this repatchable,
	// we only need to keep the last parsed JSON object around to
	// provide the "backing memory" for the ID strings.
	static json_t *backing_obj = NULL;

	json_t* new_obj = stack_game_json_resolve("stringlocs.js", NULL);
	const char *key;
	const json_t *val;

	AcquireSRWLockExclusive(&stringlocs_srwlock);
	stringlocs.clear();

	json_object_foreach(new_obj, key, val) {
		// TODO: For now, we're nagging developers with one message box for
		// every single parse error. It'd certainly be better if we gathered
		// all errors into a single message box to be printed at the end of
		// the parsing, and even had a somewhat generic solution if we do
		// more of these conversions.
#define stringlocs_log_error(msg) \
	log_mboxf(NULL, MB_OK | MB_ICONEXCLAMATION, \
		"Error parsing stringlocs.js: \"%s\" " msg".", key, sizeof(size_t) * 8 \
	)

		if(!json_is_string(val)) {
			stringlocs_log_error("must be a JSON string");
			continue;
		}
		uint8_t error;
		const char *addr = (const char *)str_address_value(key, &error);
		if(error == STR_ADDRESS_ERROR_NONE) {
			stringlocs[addr] = json_string_value(val);
		}
		if(error & STR_ADDRESS_ERROR_OVERFLOW) {
			stringlocs_log_error("exceeds %d bits");
		}
		if(error & STR_ADDRESS_ERROR_GARBAGE) {
			stringlocs_log_error("has garbage at the end");
		}
#undef stringlocs_log_error
	}

	json_decref(backing_obj);
	backing_obj = new_obj;

	ReleaseSRWLockExclusive(&stringlocs_srwlock);
}

const json_t* strings_get(const char *id)
{
	return json_object_get(jsondata_get("stringdefs.js"), id);
}

const char* strings_lookup(const char *in, size_t *out_len)
{
	const char *ret = in;

	if(!in) {
		return in;
	}

	AcquireSRWLockShared(&stringlocs_srwlock);
	auto id_key = stringlocs.find(in);
	if(id_key != stringlocs.end()) {
		const char *new_str = json_string_value(strings_get(id_key->second));
		if(new_str && new_str[0]) {
			ret = new_str;
		}
	}
	ReleaseSRWLockShared(&stringlocs_srwlock);

	if(out_len) {
		*out_len = strlen(ret) + 1;
	}
	return ret;
}

void strings_va_lookup(va_list va, const char *format)
{
	const char *p = format;
	while(*p) {
		printf_format_t fmt;
		int i;

		// Skip characters before '%'
		for(; *p && *p != '%'; p++);
		if(!*p) {
			break;
		}
		// *p == '%' here
		p++;

		// output a single '%' character
		if(*p == '%') {
			p++;
			continue;
		}
		p = printf_format_parse(&fmt, p);
		for(i = 0; i < fmt.argc_before_type; i++) {
			va_arg(va, int);
		}
		if(fmt.type == 's' || fmt.type == 'S') {
			*(const char**)va = strings_lookup(*(const char**)va, NULL);
		}
		for(i = 0; i < fmt.type_size_in_ints; i++) {
			va_arg(va, int);
		}
	}
}

char* strings_storage_get(const size_t slot, size_t min_len)
{
	storage_string_t *ret = NULL;
	char addr_key[addr_key_len];

	itoa(slot, addr_key, 16);
	ret = (storage_string_t*)json_object_get_hex(strings_storage, addr_key);

	// MSVCRT's realloc implementation moves the buffer every time, even if the
	// new length is shorter...
	if(!ret || (min_len && ret->len < min_len)) {
		storage_string_t *ret_new = (storage_string_t*)realloc(ret, min_len + sizeof(storage_string_t));
		// Yes, this correctly handles a realloc failure.
		if(ret_new) {
			ret_new->len = min_len;
			if(!ret) {
				ret_new->str = 0;
			}
			json_object_set_new(strings_storage, addr_key, json_integer((size_t)ret_new));
			ret = ret_new;
		}
	}
	if(ret) {
		return &ret->str;
	}
	return NULL;
}

const char* strings_vsprintf(const size_t slot, const char *format, va_list va)
{
	char *ret = NULL;
	size_t str_len;

	format = strings_lookup(format, NULL);
	strings_va_lookup(va, format);

	if(!format) {
		return NULL;
	}
	str_len = _vscprintf(format, va) + 1;

	ret = strings_storage_get(slot, str_len);
	if(ret) {
		vsprintf(ret, format, va);
		return ret;
	}
	// Try to save the situation at least somewhat...
	return format;
}

const char* strings_vsprintf_msvcrt14(const char *format, const size_t slot, va_list va)
{
	return strings_vsprintf(slot, format, va);
}

const char* strings_sprintf(const size_t slot, const char *format, ...)
{
	va_list va;
	const char *ret;
	va_start(va, format);
	ret = strings_vsprintf(slot, format, va);
	return ret;
}

const char* strings_strclr(const size_t slot)
{
	char *ret = strings_storage_get(slot, 0);
	if(ret) {
		ret[0] = 0;
	}
	return ret;
}

const char* strings_strcat(const size_t slot, const char *src)
{
	char *ret = strings_storage_get(slot, 0);
	size_t ret_len = strlen(ret);
	size_t src_len;

	src = strings_lookup(src, &src_len);

	ret = strings_storage_get(slot, ret_len + src_len);
	if(ret) {
		strncpy(ret + ret_len, src, src_len);
		return ret;
	}
	// Try to save the situation at least somewhat...
	return src;
}

const char* strings_replace(const size_t slot, const char *src, const char *dst)
{
	char *ret = strings_storage_get(slot, 0);
	dst = dst ? dst : "";
	if(src && ret) {
		size_t src_len = strlen(src);
		size_t dst_len = strlen(dst);
		while(ret) {
			char *src_pos = NULL;
			char *copy_pos = NULL;
			char *rest_pos = NULL;
			size_t ret_len = strlen(ret);
			// We do this first since the string address might change after
			// reallocation, thus invalidating the strstr() result
			ret = strings_storage_get(slot, ret_len + dst_len);
			if(!ret) {
				break;
			}
			src_pos = strstr(ret, src);
			if(!src_pos) {
				break;
			}
			copy_pos = src_pos + dst_len;
			rest_pos = src_pos + src_len;
			memmove(copy_pos, rest_pos, strlen(rest_pos) + 1);
			memcpy(src_pos, dst, dst_len);
		}
	}
	// Try to save the situation at least somewhat...
	return ret ? ret : dst;
}

/// String lookup hooks
/// -------------------
int WINAPI strings_MessageBoxA(
	HWND hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT uType
)
{
	lpText = strings_lookup(lpText, NULL);
	lpCaption = strings_lookup(lpCaption, NULL);
	return chain_MessageBoxU(hWnd, lpText, lpCaption, uType);
}
/// -------------------

void strings_mod_init(void)
{
	jsondata_add("stringdefs.js");
	stringlocs_reparse();
	strings_storage = json_object();
}

void strings_mod_detour(void)
{
	detour_chain("user32.dll", 1,
		"MessageBoxA", strings_MessageBoxA, &chain_MessageBoxU,
		NULL
	);
}

void strings_mod_repatch(json_t *files_changed)
{
	const char *key;
	const json_t *val;
	json_object_foreach(files_changed, key, val) {
		if(strstr(key, "/stringlocs.")) {
			stringlocs_reparse();
		}
	}
}

void strings_mod_exit(void)
{
	const char *key;
	json_t *val;

	json_object_foreach(strings_storage, key, val) {
		storage_string_t *p = (storage_string_t*)json_hex_value(val);
		SAFE_FREE(p);
	}
	strings_storage = json_decref_safe(strings_storage);
}
<commit_msg>Use a std::unordered_map for persistent storage strings.<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Persistent string storage, and translation of hardcoded strings.
  */

#include "thcrap.h"
#include <unordered_map>

/// Detour chains
/// -------------
W32U8_DETOUR_CHAIN_DEF(MessageBox);
/// -------------

// Length-prefixed string object used for persistent storage
typedef struct {
	size_t len;
	char str;
} storage_string_t;

std::unordered_map<size_t, storage_string_t *> strings_storage;

SRWLOCK stringlocs_srwlock = {SRWLOCK_INIT};
std::unordered_map<const char *, const char *> stringlocs;

#define addr_key_len 2 + (sizeof(void*) * 2) + 1

void stringlocs_reparse(void)
{
	// Since we can't use the jsondata module to make this repatchable,
	// we only need to keep the last parsed JSON object around to
	// provide the "backing memory" for the ID strings.
	static json_t *backing_obj = NULL;

	json_t* new_obj = stack_game_json_resolve("stringlocs.js", NULL);
	const char *key;
	const json_t *val;

	AcquireSRWLockExclusive(&stringlocs_srwlock);
	stringlocs.clear();

	json_object_foreach(new_obj, key, val) {
		// TODO: For now, we're nagging developers with one message box for
		// every single parse error. It'd certainly be better if we gathered
		// all errors into a single message box to be printed at the end of
		// the parsing, and even had a somewhat generic solution if we do
		// more of these conversions.
#define stringlocs_log_error(msg) \
	log_mboxf(NULL, MB_OK | MB_ICONEXCLAMATION, \
		"Error parsing stringlocs.js: \"%s\" " msg".", key, sizeof(size_t) * 8 \
	)

		if(!json_is_string(val)) {
			stringlocs_log_error("must be a JSON string");
			continue;
		}
		uint8_t error;
		const char *addr = (const char *)str_address_value(key, &error);
		if(error == STR_ADDRESS_ERROR_NONE) {
			stringlocs[addr] = json_string_value(val);
		}
		if(error & STR_ADDRESS_ERROR_OVERFLOW) {
			stringlocs_log_error("exceeds %d bits");
		}
		if(error & STR_ADDRESS_ERROR_GARBAGE) {
			stringlocs_log_error("has garbage at the end");
		}
#undef stringlocs_log_error
	}

	json_decref(backing_obj);
	backing_obj = new_obj;

	ReleaseSRWLockExclusive(&stringlocs_srwlock);
}

const json_t* strings_get(const char *id)
{
	return json_object_get(jsondata_get("stringdefs.js"), id);
}

const char* strings_lookup(const char *in, size_t *out_len)
{
	const char *ret = in;

	if(!in) {
		return in;
	}

	AcquireSRWLockShared(&stringlocs_srwlock);
	auto id_key = stringlocs.find(in);
	if(id_key != stringlocs.end()) {
		const char *new_str = json_string_value(strings_get(id_key->second));
		if(new_str && new_str[0]) {
			ret = new_str;
		}
	}
	ReleaseSRWLockShared(&stringlocs_srwlock);

	if(out_len) {
		*out_len = strlen(ret) + 1;
	}
	return ret;
}

void strings_va_lookup(va_list va, const char *format)
{
	const char *p = format;
	while(*p) {
		printf_format_t fmt;
		int i;

		// Skip characters before '%'
		for(; *p && *p != '%'; p++);
		if(!*p) {
			break;
		}
		// *p == '%' here
		p++;

		// output a single '%' character
		if(*p == '%') {
			p++;
			continue;
		}
		p = printf_format_parse(&fmt, p);
		for(i = 0; i < fmt.argc_before_type; i++) {
			va_arg(va, int);
		}
		if(fmt.type == 's' || fmt.type == 'S') {
			*(const char**)va = strings_lookup(*(const char**)va, NULL);
		}
		for(i = 0; i < fmt.type_size_in_ints; i++) {
			va_arg(va, int);
		}
	}
}

char* strings_storage_get(const size_t slot, size_t min_len)
{
	storage_string_t *ret = nullptr;
	auto stored = strings_storage.find(slot);

	// MSVCRT's realloc implementation moves the buffer every time, even if the
	// new length is shorter...
	if(stored == strings_storage.end() || (min_len && stored->second->len < min_len)) {
		auto *ret_new = (storage_string_t*)realloc(ret, min_len + sizeof(storage_string_t));
		// Yes, this correctly handles a realloc failure.
		if(ret_new) {
			ret_new->len = min_len;
			if(!ret) {
				ret_new->str = 0;
			}
			strings_storage[slot] = ret_new;
			ret = ret_new;
		}
	} else {
		ret = stored->second;
	}
	if(ret) {
		return &ret->str;
	}
	return nullptr;
}

const char* strings_vsprintf(const size_t slot, const char *format, va_list va)
{
	char *ret = NULL;
	size_t str_len;

	format = strings_lookup(format, NULL);
	strings_va_lookup(va, format);

	if(!format) {
		return NULL;
	}
	str_len = _vscprintf(format, va) + 1;

	ret = strings_storage_get(slot, str_len);
	if(ret) {
		vsprintf(ret, format, va);
		return ret;
	}
	// Try to save the situation at least somewhat...
	return format;
}

const char* strings_vsprintf_msvcrt14(const char *format, const size_t slot, va_list va)
{
	return strings_vsprintf(slot, format, va);
}

const char* strings_sprintf(const size_t slot, const char *format, ...)
{
	va_list va;
	const char *ret;
	va_start(va, format);
	ret = strings_vsprintf(slot, format, va);
	return ret;
}

const char* strings_strclr(const size_t slot)
{
	char *ret = strings_storage_get(slot, 0);
	if(ret) {
		ret[0] = 0;
	}
	return ret;
}

const char* strings_strcat(const size_t slot, const char *src)
{
	char *ret = strings_storage_get(slot, 0);
	size_t ret_len = strlen(ret);
	size_t src_len;

	src = strings_lookup(src, &src_len);

	ret = strings_storage_get(slot, ret_len + src_len);
	if(ret) {
		strncpy(ret + ret_len, src, src_len);
		return ret;
	}
	// Try to save the situation at least somewhat...
	return src;
}

const char* strings_replace(const size_t slot, const char *src, const char *dst)
{
	char *ret = strings_storage_get(slot, 0);
	dst = dst ? dst : "";
	if(src && ret) {
		size_t src_len = strlen(src);
		size_t dst_len = strlen(dst);
		while(ret) {
			char *src_pos = NULL;
			char *copy_pos = NULL;
			char *rest_pos = NULL;
			size_t ret_len = strlen(ret);
			// We do this first since the string address might change after
			// reallocation, thus invalidating the strstr() result
			ret = strings_storage_get(slot, ret_len + dst_len);
			if(!ret) {
				break;
			}
			src_pos = strstr(ret, src);
			if(!src_pos) {
				break;
			}
			copy_pos = src_pos + dst_len;
			rest_pos = src_pos + src_len;
			memmove(copy_pos, rest_pos, strlen(rest_pos) + 1);
			memcpy(src_pos, dst, dst_len);
		}
	}
	// Try to save the situation at least somewhat...
	return ret ? ret : dst;
}

/// String lookup hooks
/// -------------------
int WINAPI strings_MessageBoxA(
	HWND hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT uType
)
{
	lpText = strings_lookup(lpText, NULL);
	lpCaption = strings_lookup(lpCaption, NULL);
	return chain_MessageBoxU(hWnd, lpText, lpCaption, uType);
}
/// -------------------

void strings_mod_init(void)
{
	jsondata_add("stringdefs.js");
	stringlocs_reparse();
}

void strings_mod_detour(void)
{
	detour_chain("user32.dll", 1,
		"MessageBoxA", strings_MessageBoxA, &chain_MessageBoxU,
		NULL
	);
}

void strings_mod_repatch(json_t *files_changed)
{
	const char *key;
	const json_t *val;
	json_object_foreach(files_changed, key, val) {
		if(strstr(key, "/stringlocs.")) {
			stringlocs_reparse();
		}
	}
}

void strings_mod_exit(void)
{
	for(auto& i : strings_storage) {
		SAFE_FREE(i.second);
	}
	strings_storage.clear();
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkExtractSelectedGraph.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkExtractSelectedGraph.h"

#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkConvertSelection.h"
#include "vtkDataArray.h"
#include "vtkEdgeListIterator.h"
#include "vtkEventForwarderCommand.h"
#include "vtkExtractSelection.h"
#include "vtkGraph.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMutableDirectedGraph.h"
#include "vtkMutableUndirectedGraph.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkSelection.h"
#include "vtkSignedCharArray.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"
#include "vtkTree.h"
#include "vtkVertexListIterator.h"

#include <vtksys/stl/map>

vtkCxxRevisionMacro(vtkExtractSelectedGraph, "1.18");
vtkStandardNewMacro(vtkExtractSelectedGraph);
//----------------------------------------------------------------------------
vtkExtractSelectedGraph::vtkExtractSelectedGraph()
{
  this->SetNumberOfInputPorts(2);
  this->RemoveIsolatedVertices = true;
}

//----------------------------------------------------------------------------
vtkExtractSelectedGraph::~vtkExtractSelectedGraph()
{
}

//----------------------------------------------------------------------------
int vtkExtractSelectedGraph::FillInputPortInformation(int port, vtkInformation* info)
{
  if (port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph");
    return 1;
    }
  else if (port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkSelection");
    return 1;
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkExtractSelectedGraph::SetSelectionConnection(vtkAlgorithmOutput* in)
{
  this->SetInputConnection(1, in);
}

//----------------------------------------------------------------------------
int vtkExtractSelectedGraph::RequestDataObject(
  vtkInformation*,
  vtkInformationVector** inputVector ,
  vtkInformationVector* outputVector)
{
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  if (!inInfo)
    {
    return 0;
    }
  vtkGraph *input = vtkGraph::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (input)
    {
    vtkInformation* info = outputVector->GetInformationObject(0);
    vtkGraph *output = vtkGraph::SafeDownCast(
      info->Get(vtkDataObject::DATA_OBJECT()));

    // Output a vtkDirectedGraph if the input is a tree.
    if (!output
        || (vtkTree::SafeDownCast(input) && !vtkDirectedGraph::SafeDownCast(output))
        || (!vtkTree::SafeDownCast(input) && !output->IsA(input->GetClassName())))
      {
      if (vtkTree::SafeDownCast(input))
        {
        output = vtkDirectedGraph::New();
        }
      else
        {
        output = input->NewInstance();
        }
      output->SetPipelineInformation(info);
      output->Delete();
      this->GetOutputPortInformation(0)->Set(
        vtkDataObject::DATA_EXTENT_TYPE(), output->GetExtentType());
      }
    return 1;
    }
  return 0;
}

//----------------------------------------------------------------------------
int vtkExtractSelectedGraph::RequestData(
  vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  vtkGraph* input = vtkGraph::GetData(inputVector[0]);
  vtkSelection* selection = vtkSelection::GetData(inputVector[1]);

  // If there is nothing in the list, there is nothing to select.
  vtkAbstractArray* list = selection->GetSelectionList();
  if (!list || list->GetNumberOfTuples() == 0)
    {
    return 1;
    }

  int inverse = 0;
  if(selection->GetProperties()->Has(vtkSelection::INVERSE()))
    {
    inverse = selection->GetProperties()->Get(vtkSelection::INVERSE());
    }

  // If it is a selection with multiple parts, find a point or cell
  // child selection, with preference to points.
  if (selection->GetContentType() == vtkSelection::SELECTIONS)
    {
    vtkSelection* child = 0;
    for (unsigned int i = 0; i < selection->GetNumberOfChildren(); i++)
      {
      vtkSelection* cur = selection->GetChild(i);
      if (cur->GetFieldType() == vtkSelection::POINT)
        {
        child = cur;
        break;
        }
      else if (cur->GetFieldType() == vtkSelection::CELL)
        {
        child = cur;
        }
      }
    selection = child;
    }

  // Convert the selection to an INDICES selection
  vtkSmartPointer<vtkSelection> indexSelection;
  indexSelection.TakeReference(
    vtkConvertSelection::ToIndexSelection(selection, input));
  if (!indexSelection)
    {
    vtkErrorMacro("Selection conversion to INDICES failed.");
    indexSelection->Delete();
    return 0;
    }

  vtkAbstractArray* arr = indexSelection->GetSelectionList();
  if (arr == NULL)
    {
    vtkErrorMacro("Selection list not found.");
    return 0;
    }
  vtkIdTypeArray* selectArr = vtkIdTypeArray::SafeDownCast(arr);
  if (selectArr == NULL)
    {
    vtkErrorMacro("Selection list must be of type vtkIdTypeArray.");
    return 0;
    }
  vtkIdType selectSize = selectArr->GetNumberOfTuples();

  bool directed = false;
  if (vtkDirectedGraph::SafeDownCast(input))
    {
    directed = true;
    }

  vtkSmartPointer<vtkMutableDirectedGraph> dirBuilder =
    vtkSmartPointer<vtkMutableDirectedGraph>::New();
  vtkSmartPointer<vtkMutableUndirectedGraph> undirBuilder =
    vtkSmartPointer<vtkMutableUndirectedGraph>::New();

  if (selection->GetProperties()->Has(vtkSelection::FIELD_TYPE()) &&
      selection->GetProperties()->Get(vtkSelection::FIELD_TYPE()) == vtkSelection::EDGE)
    {
    //
    // Edge selection
    //

    // Copy all vertices
    for (vtkIdType v = 0; v < input->GetNumberOfVertices(); ++v)
      {
      if (directed)
        {
        dirBuilder->AddVertex();
        }
      else
        {
        undirBuilder->AddVertex();
        }
      }

    vtkDataSetAttributes *inputEdgeData = input->GetEdgeData();
    vtkDataSetAttributes *builderEdgeData = 0;
    if (directed)
      {
      builderEdgeData = dirBuilder->GetEdgeData();
      }
    else
      {
      builderEdgeData = undirBuilder->GetEdgeData();
      }

    builderEdgeData->CopyAllocate(inputEdgeData);

    // Copy unselected edges
    vtkSmartPointer<vtkEdgeListIterator> edges =
      vtkSmartPointer<vtkEdgeListIterator>::New();
    input->GetEdges(edges);
    while (edges->HasNext())
      {
      vtkEdgeType e = edges->Next();

      if ((inverse && selectArr->LookupValue(e.Id) < 0) ||
          (!inverse && selectArr->LookupValue(e.Id) >= 0))
        {
        vtkEdgeType outputEdge;
        if (directed)
          {
          outputEdge = dirBuilder->AddEdge(e.Source, e.Target);
          }
        else
          {
          outputEdge = undirBuilder->AddEdge(e.Source, e.Target);
          }
        builderEdgeData->CopyData(inputEdgeData, e.Id, outputEdge.Id);
        }
      }

    // Remove isolated vertices
    if (this->RemoveIsolatedVertices)
      {
      // TODO: Implement this (requires rebuilding the graph without the
      // isolated vertices).
      vtkErrorMacro(<<"RemoveIsolatedVertices is not implemented.");
      }
    else
      {
      if (directed)
        {
        dirBuilder->GetVertexData()->PassData(input->GetVertexData());
        dirBuilder->GetPoints()->ShallowCopy(input->GetPoints());
        }
      else
        {
        undirBuilder->GetVertexData()->PassData(input->GetVertexData());
        undirBuilder->GetPoints()->ShallowCopy(input->GetPoints());
        }
      }
    }
  else
    {
    //
    // Vertex selection
    //

    double pt[3];
    vtkPoints *inputPoints = input->GetPoints();
    vtkSmartPointer<vtkPoints> outputPoints =
      vtkSmartPointer<vtkPoints>::New();
    vtkDataSetAttributes *inputVertexData = input->GetVertexData();
    vtkDataSetAttributes *builderVertexData = 0;
    if (directed)
      {
      builderVertexData = dirBuilder->GetVertexData();
      }
    else
      {
      builderVertexData = undirBuilder->GetVertexData();
      }
    builderVertexData->CopyAllocate(inputVertexData);
    vtksys_stl::map<vtkIdType, vtkIdType> idMap;

    // Copy unselected vertices
    if(inverse)
      {
      vtkSmartPointer<vtkVertexListIterator> vertices =
        vtkSmartPointer<vtkVertexListIterator>::New();
      input->GetVertices(vertices);
      while (vertices->HasNext())
        {
        vtkIdType i = vertices->Next();
        if(selectArr->LookupValue(i) < 0)
          {
          vtkIdType outputVertex = -1;
          if (directed)
            {
            outputVertex = dirBuilder->AddVertex();
            }
          else
            {
            outputVertex = undirBuilder->AddVertex();
            }
          builderVertexData->CopyData(inputVertexData, i, outputVertex);
          idMap[i] = outputVertex;
          inputPoints->GetPoint(i, pt);
          outputPoints->InsertNextPoint(pt);
          }
        }
      }
    // Copy selected vertices
    else
      {
      for (vtkIdType i = 0; i < selectSize; i++)
        {
        vtkIdType inputVertex = selectArr->GetValue(i);
        if (inputVertex < input->GetNumberOfVertices())
          {
          vtkIdType outputVertex = -1;
          if (directed)
            {
            outputVertex = dirBuilder->AddVertex();
            }
          else
            {
            outputVertex = undirBuilder->AddVertex();
            }
          builderVertexData->CopyData(inputVertexData, inputVertex, outputVertex);
          idMap[inputVertex] = outputVertex;
          inputPoints->GetPoint(inputVertex, pt);
          outputPoints->InsertNextPoint(pt);
          }
        }
      }
    if (directed)
      {
      dirBuilder->SetPoints(outputPoints);
      }
    else
      {
      undirBuilder->SetPoints(outputPoints);
      }

    // Copy edges whose source and target are selected.
    vtkDataSetAttributes *inputEdgeData = input->GetEdgeData();
    vtkDataSetAttributes *builderEdgeData = 0;
    if (directed)
      {
      builderEdgeData = dirBuilder->GetEdgeData();
      }
    else
      {
      builderEdgeData = undirBuilder->GetEdgeData();
      }
    builderEdgeData->CopyAllocate(inputEdgeData);

    vtkSmartPointer<vtkEdgeListIterator> edges =
      vtkSmartPointer<vtkEdgeListIterator>::New();
    input->GetEdges(edges);
    while (edges->HasNext())
      {
      vtkEdgeType e = edges->Next();
      if (idMap.count(e.Source) > 0 && idMap.count(e.Target) > 0)
        {
        vtkEdgeType outputEdge;
        if (directed)
          {
          outputEdge = dirBuilder->AddEdge(idMap[e.Source], idMap[e.Target]);
          }
        else
          {
          outputEdge = undirBuilder->AddEdge(idMap[e.Source], idMap[e.Target]);
          }
        builderEdgeData->CopyData(inputEdgeData, e.Id, outputEdge.Id);
        }
      }
    }

  // Pass constructed graph to output.
  vtkGraph* output = vtkGraph::GetData(outputVector);
  if (directed)
    {
    if (!output->CheckedShallowCopy(dirBuilder))
      {
      vtkErrorMacro(<<"Invalid graph structure.");
      return 0;
      }
    }
  else
    {
    if (!output->CheckedShallowCopy(undirBuilder))
      {
      vtkErrorMacro(<<"Invalid graph structure.");
      return 0;
      }
    }
  output->GetFieldData()->PassData(input->GetFieldData());

  // Clean up
  output->Squeeze();

  return 1;
}

//----------------------------------------------------------------------------
void vtkExtractSelectedGraph::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "RemoveIsolatedVertices: "
     << (this->RemoveIsolatedVertices ? "on" : "off") << endl;
}
<commit_msg>ENH: Implement RemoveIsolatedVertices feature.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkExtractSelectedGraph.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkExtractSelectedGraph.h"

#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkConvertSelection.h"
#include "vtkDataArray.h"
#include "vtkEdgeListIterator.h"
#include "vtkEventForwarderCommand.h"
#include "vtkExtractSelection.h"
#include "vtkGraph.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMutableDirectedGraph.h"
#include "vtkMutableUndirectedGraph.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkSelection.h"
#include "vtkSignedCharArray.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"
#include "vtkTree.h"
#include "vtkVertexListIterator.h"

#include <vtksys/stl/map>
#include <vtkstd/vector>

vtkCxxRevisionMacro(vtkExtractSelectedGraph, "1.19");
vtkStandardNewMacro(vtkExtractSelectedGraph);
//----------------------------------------------------------------------------
vtkExtractSelectedGraph::vtkExtractSelectedGraph()
{
  this->SetNumberOfInputPorts(2);
  this->RemoveIsolatedVertices = true;
}

//----------------------------------------------------------------------------
vtkExtractSelectedGraph::~vtkExtractSelectedGraph()
{
}

//----------------------------------------------------------------------------
int vtkExtractSelectedGraph::FillInputPortInformation(int port, vtkInformation* info)
{
  if (port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph");
    return 1;
    }
  else if (port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkSelection");
    return 1;
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkExtractSelectedGraph::SetSelectionConnection(vtkAlgorithmOutput* in)
{
  this->SetInputConnection(1, in);
}

//----------------------------------------------------------------------------
int vtkExtractSelectedGraph::RequestDataObject(
  vtkInformation*,
  vtkInformationVector** inputVector ,
  vtkInformationVector* outputVector)
{
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  if (!inInfo)
    {
    return 0;
    }
  vtkGraph *input = vtkGraph::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (input)
    {
    vtkInformation* info = outputVector->GetInformationObject(0);
    vtkGraph *output = vtkGraph::SafeDownCast(
      info->Get(vtkDataObject::DATA_OBJECT()));

    // Output a vtkDirectedGraph if the input is a tree.
    if (!output
        || (vtkTree::SafeDownCast(input) && !vtkDirectedGraph::SafeDownCast(output))
        || (!vtkTree::SafeDownCast(input) && !output->IsA(input->GetClassName())))
      {
      if (vtkTree::SafeDownCast(input))
        {
        output = vtkDirectedGraph::New();
        }
      else
        {
        output = input->NewInstance();
        }
      output->SetPipelineInformation(info);
      output->Delete();
      this->GetOutputPortInformation(0)->Set(
        vtkDataObject::DATA_EXTENT_TYPE(), output->GetExtentType());
      }
    return 1;
    }
  return 0;
}

//----------------------------------------------------------------------------
int vtkExtractSelectedGraph::RequestData(
  vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  vtkGraph* input = vtkGraph::GetData(inputVector[0]);
  vtkSelection* selection = vtkSelection::GetData(inputVector[1]);

  // If there is nothing in the list, there is nothing to select.
  vtkAbstractArray* list = selection->GetSelectionList();
  if (!list || list->GetNumberOfTuples() == 0)
    {
    return 1;
    }

  int inverse = 0;
  if(selection->GetProperties()->Has(vtkSelection::INVERSE()))
    {
    inverse = selection->GetProperties()->Get(vtkSelection::INVERSE());
    }

  // If it is a selection with multiple parts, find a point or cell
  // child selection, with preference to points.
  if (selection->GetContentType() == vtkSelection::SELECTIONS)
    {
    vtkSelection* child = 0;
    for (unsigned int i = 0; i < selection->GetNumberOfChildren(); i++)
      {
      vtkSelection* cur = selection->GetChild(i);
      if (cur->GetFieldType() == vtkSelection::VERTEX)
        {
        child = cur;
        break;
        }
      else if (cur->GetFieldType() == vtkSelection::EDGE)
        {
        child = cur;
        }
      }
    selection = child;
    }

  // Convert the selection to an INDICES selection
  vtkSmartPointer<vtkSelection> indexSelection;
  indexSelection.TakeReference(
    vtkConvertSelection::ToIndexSelection(selection, input));
  if (!indexSelection)
    {
    vtkErrorMacro("Selection conversion to INDICES failed.");
    indexSelection->Delete();
    return 0;
    }

  vtkAbstractArray* arr = indexSelection->GetSelectionList();
  if (arr == NULL)
    {
    vtkErrorMacro("Selection list not found.");
    return 0;
    }
  vtkIdTypeArray* selectArr = vtkIdTypeArray::SafeDownCast(arr);
  if (selectArr == NULL)
    {
    vtkErrorMacro("Selection list must be of type vtkIdTypeArray.");
    return 0;
    }
  vtkIdType selectSize = selectArr->GetNumberOfTuples();

  bool directed = false;
  if (vtkDirectedGraph::SafeDownCast(input))
    {
    directed = true;
    }

  vtkSmartPointer<vtkMutableDirectedGraph> dirBuilder =
    vtkSmartPointer<vtkMutableDirectedGraph>::New();
  vtkSmartPointer<vtkMutableUndirectedGraph> undirBuilder =
    vtkSmartPointer<vtkMutableUndirectedGraph>::New();

  if (selection->GetProperties()->Has(vtkSelection::FIELD_TYPE()) &&
      selection->GetProperties()->Get(vtkSelection::FIELD_TYPE()) == vtkSelection::EDGE)
    {
    //
    // Edge selection
    //

    vtkDataSetAttributes *inputEdgeData = input->GetEdgeData();
    vtkDataSetAttributes *builderEdgeData = 0;
    if (directed)
      {
      builderEdgeData = dirBuilder->GetEdgeData();
      }
    else
      {
      builderEdgeData = undirBuilder->GetEdgeData();
      }

    builderEdgeData->CopyAllocate(inputEdgeData);

    // Handle the case where we are not outputing isolated vertices separately:
    if(this->RemoveIsolatedVertices)
      {
      // Create and initialize vector that keeps track of which
      // vertices are connected by an edge (1) and which aren't (0).

      unsigned int idx;
      vtkstd::vector<int> connectedVertices;
      for(int j=0; j<input->GetNumberOfVertices(); ++j)
        {
        connectedVertices.push_back(0);
        }

      vtkSmartPointer<vtkEdgeListIterator> edgeIter =
        vtkSmartPointer<vtkEdgeListIterator>::New();
      input->GetEdges(edgeIter);
      while (edgeIter->HasNext())
        {
        vtkEdgeType e = edgeIter->Next();

        if ((inverse && selectArr->LookupValue(e.Id) < 0) ||
            (!inverse && selectArr->LookupValue(e.Id) >= 0))
          {
          connectedVertices[e.Source] = 1;
          connectedVertices[e.Target] = 1;
          }
        }

      // Create a mapping between the input vertex id and the output vertex id.
      // Right now we rely on the fact that the input vertex ids are consecutive
      // integers from 0 to NUMBER_OF_VERTICES -1. So the index into the
      // vertexMap vector below actually represents the input vertex id.

      int numConnected = 0;
      vtkstd::vector<int> vertexMap;
      for(idx=0; idx<connectedVertices.size(); ++idx)
        {
        vertexMap.push_back(numConnected);

        if(connectedVertices[idx] == 1)
          {
          numConnected++;
          }
        }

      // Copy only the connected vertices
      for (int j = 0; j < numConnected; ++j)
        {
        if (directed)
          {
          dirBuilder->AddVertex();
          }
        else
          {
          undirBuilder->AddVertex();
          }
        }

      // Construct the output vertex data and vtkPoints using the new vertex ids

      vtkPoints* newPoints = vtkPoints::New();
      newPoints->SetNumberOfPoints(numConnected);

      if (directed)
        {
        dirBuilder->GetVertexData()->SetNumberOfTuples(numConnected);
        for (idx = 0; idx<connectedVertices.size(); idx++)
          {
          if(connectedVertices[idx]==1)
            {
            dirBuilder->GetVertexData()->SetTuple(vertexMap[idx], idx, input->GetVertexData());
            newPoints->SetPoint(vertexMap[idx], input->GetPoints()->GetPoint(idx));
            }
          }
        dirBuilder->SetPoints(newPoints);
        }
      else
        {
        undirBuilder->GetVertexData()->SetNumberOfTuples(numConnected);
        for (idx = 0; idx<connectedVertices.size(); idx++)
          {
          if(connectedVertices[idx]==1)
            {
            undirBuilder->GetVertexData()->SetTuple(vertexMap[idx], idx, input->GetVertexData());
            newPoints->SetPoint(vertexMap[idx], input->GetPoints()->GetPoint(idx));
            }
          }
        undirBuilder->SetPoints(newPoints);
        }

      newPoints->Delete();

      // Now actually copy the edges (only the selected ones)
      // using the new vertex ids.

      vtkSmartPointer<vtkEdgeListIterator> edges =
        vtkSmartPointer<vtkEdgeListIterator>::New();
      input->GetEdges(edges);
      while (edges->HasNext())
        {
        vtkEdgeType e = edges->Next();

        if ((inverse && selectArr->LookupValue(e.Id) < 0) ||
            (!inverse && selectArr->LookupValue(e.Id) >= 0))
          {
          vtkEdgeType outputEdge;
          if (directed)
            {
            outputEdge = dirBuilder->AddEdge(vertexMap[e.Source], vertexMap[e.Target]);
            }
          else
            {
            outputEdge = undirBuilder->AddEdge(vertexMap[e.Source], vertexMap[e.Target]);
            }
          builderEdgeData->CopyData(inputEdgeData, e.Id, outputEdge.Id);
          }
        }
      }
    else  // !this->RemoveIsolatedVertices
      {

      // Copy all vertices
      for (vtkIdType v = 0; v < input->GetNumberOfVertices(); ++v)
        {
        if (directed)
          {
          dirBuilder->AddVertex();
          }
        else
          {
          undirBuilder->AddVertex();
          }
        }

      // Copy unselected edges
      vtkSmartPointer<vtkEdgeListIterator> edges =
        vtkSmartPointer<vtkEdgeListIterator>::New();
      input->GetEdges(edges);
      while (edges->HasNext())
        {
        vtkEdgeType e = edges->Next();

        if ((inverse && selectArr->LookupValue(e.Id) < 0) ||
            (!inverse && selectArr->LookupValue(e.Id) >= 0))
          {
          vtkEdgeType outputEdge;
          if (directed)
            {
            outputEdge = dirBuilder->AddEdge(e.Source, e.Target);
            }
          else
            {
            outputEdge = undirBuilder->AddEdge(e.Source, e.Target);
            }
          builderEdgeData->CopyData(inputEdgeData, e.Id, outputEdge.Id);
          }
        }

      if (directed)
        {
        dirBuilder->GetVertexData()->PassData(input->GetVertexData());
        dirBuilder->GetPoints()->ShallowCopy(input->GetPoints());
        }
      else
        {
        undirBuilder->GetVertexData()->PassData(input->GetVertexData());
        undirBuilder->GetPoints()->ShallowCopy(input->GetPoints());
        }
      }
    }
  else
    {
    //
    // Vertex selection
    //

    double pt[3];
    vtkPoints *inputPoints = input->GetPoints();
    vtkSmartPointer<vtkPoints> outputPoints =
      vtkSmartPointer<vtkPoints>::New();
    vtkDataSetAttributes *inputVertexData = input->GetVertexData();
    vtkDataSetAttributes *builderVertexData = 0;
    if (directed)
      {
      builderVertexData = dirBuilder->GetVertexData();
      }
    else
      {
      builderVertexData = undirBuilder->GetVertexData();
      }
    builderVertexData->CopyAllocate(inputVertexData);
    vtksys_stl::map<vtkIdType, vtkIdType> idMap;

    // Copy unselected vertices
    if(inverse)
      {
      vtkSmartPointer<vtkVertexListIterator> vertices =
        vtkSmartPointer<vtkVertexListIterator>::New();
      input->GetVertices(vertices);
      while (vertices->HasNext())
        {
        vtkIdType i = vertices->Next();
        if(selectArr->LookupValue(i) < 0)
          {
          vtkIdType outputVertex = -1;
          if (directed)
            {
            outputVertex = dirBuilder->AddVertex();
            }
          else
            {
            outputVertex = undirBuilder->AddVertex();
            }
          builderVertexData->CopyData(inputVertexData, i, outputVertex);
          idMap[i] = outputVertex;
          inputPoints->GetPoint(i, pt);
          outputPoints->InsertNextPoint(pt);
          }
        }
      }
    // Copy selected vertices
    else
      {
      for (vtkIdType i = 0; i < selectSize; i++)
        {
        vtkIdType inputVertex = selectArr->GetValue(i);
        if (inputVertex < input->GetNumberOfVertices())
          {
          vtkIdType outputVertex = -1;
          if (directed)
            {
            outputVertex = dirBuilder->AddVertex();
            }
          else
            {
            outputVertex = undirBuilder->AddVertex();
            }
          builderVertexData->CopyData(inputVertexData, inputVertex, outputVertex);
          idMap[inputVertex] = outputVertex;
          inputPoints->GetPoint(inputVertex, pt);
          outputPoints->InsertNextPoint(pt);
          }
        }
      }
    if (directed)
      {
      dirBuilder->SetPoints(outputPoints);
      }
    else
      {
      undirBuilder->SetPoints(outputPoints);
      }

    // Copy edges whose source and target are selected.
    vtkDataSetAttributes *inputEdgeData = input->GetEdgeData();
    vtkDataSetAttributes *builderEdgeData = 0;
    if (directed)
      {
      builderEdgeData = dirBuilder->GetEdgeData();
      }
    else
      {
      builderEdgeData = undirBuilder->GetEdgeData();
      }
    builderEdgeData->CopyAllocate(inputEdgeData);

    vtkSmartPointer<vtkEdgeListIterator> edges =
      vtkSmartPointer<vtkEdgeListIterator>::New();
    input->GetEdges(edges);
    while (edges->HasNext())
      {
      vtkEdgeType e = edges->Next();
      if (idMap.count(e.Source) > 0 && idMap.count(e.Target) > 0)
        {
        vtkEdgeType outputEdge;
        if (directed)
          {
          outputEdge = dirBuilder->AddEdge(idMap[e.Source], idMap[e.Target]);
          }
        else
          {
          outputEdge = undirBuilder->AddEdge(idMap[e.Source], idMap[e.Target]);
          }
        builderEdgeData->CopyData(inputEdgeData, e.Id, outputEdge.Id);
        }
      }
    }

  // Pass constructed graph to output.
  vtkGraph* output = vtkGraph::GetData(outputVector);
  if (directed)
    {
    if (!output->CheckedShallowCopy(dirBuilder))
      {
      vtkErrorMacro(<<"Invalid graph structure.");
      return 0;
      }
    }
  else
    {
    if (!output->CheckedShallowCopy(undirBuilder))
      {
      vtkErrorMacro(<<"Invalid graph structure.");
      return 0;
      }
    }
  output->GetFieldData()->PassData(input->GetFieldData());

  // Clean up
  output->Squeeze();

  return 1;
}

//----------------------------------------------------------------------------
void vtkExtractSelectedGraph::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "RemoveIsolatedVertices: "
     << (this->RemoveIsolatedVertices ? "on" : "off") << endl;
}
<|endoftext|>


<commit_before>#include "predicator.h"
#include "planning_tool.h"

#include <boost/bind/bind.hpp>

namespace predicator_planning {

  Planner::Planner(PredicateContext *_context, unsigned int _max_iter, unsigned int _children, double _step) :
    context(_context), max_iter(_max_iter), children(_children), step(_step)
  {
    ros::NodeHandle nh;
    planServer = nh.advertiseService <
      predicator_planning::PredicatePlan::Request,
      predicator_planning::PredicatePlan::Response>
        ("/predicator/plan",
         boost::bind(&Planner::plan, *this, _1, _2));
  }

  bool Planner::plan(predicator_planning::PredicatePlan::Request &req,
                     predicator_planning::PredicatePlan::Response &res)
  {

    // get starting states
    // these are the states as recorded in the context
    // they will be updated as we go on if this takes a while -- might be bad
    std::vector<RobotState *> starting_states = context->states;

    // find the index of the current robot state
    unsigned int idx = 0;
    for (RobotModelPtr &ptr: context->robots) {
      std::cout << ptr->getName() << std::endl;
      if (ptr->getName().compare(req.robot)) {
          break;
      }
      ++idx;
    }

    // loop over
    for (unsigned int iter = 0; iter < max_iter; ++iter) {
      // either generate a starting position at random or...
      // step in a direction from a "good" position (as determined by high heuristics)

      for (unsigned int i = 0; i < children; ++i) {

      }

    }

    return true;
  }
}
<commit_msg>cleaned up constructor<commit_after>#include "predicator.h"
#include "planning_tool.h"

#include <boost/bind/bind.hpp>

namespace predicator_planning {

  Planner::Planner(PredicateContext *_context, unsigned int _max_iter, unsigned int _children, double _step) :
    context(_context), max_iter(_max_iter), children(_children), step(_step)
  {
    ros::NodeHandle nh;
    planServer = nh.advertiseService("predicator/plan", &Planner::plan, this);
  }

  bool Planner::plan(predicator_planning::PredicatePlan::Request &req,
                     predicator_planning::PredicatePlan::Response &res)
  {

    // get starting states
    // these are the states as recorded in the context
    // they will be updated as we go on if this takes a while -- might be bad
    std::vector<RobotState *> starting_states = context->states;

    // find the index of the current robot state
    unsigned int idx = 0;
    for (RobotModelPtr &ptr: context->robots) {
      std::cout << ptr->getName() << std::endl;
      if (ptr->getName().compare(req.robot)) {
        break;
      }
      ++idx;
    }

    // loop over
    for (unsigned int iter = 0; iter < max_iter; ++iter) {
      // either generate a starting position at random or...
      // step in a direction from a "good" position (as determined by high heuristics)

      for (unsigned int i = 0; i < children; ++i) {

      }

    }

    return true;
  }
}
<|endoftext|>


<commit_before>// demo.cpp : ̨Ӧóڵ㡣
//

#include <stdio.h>
#include <assert.h>
#include <map>
#include <vector>

#include "CodeAddress.h"
#include "ThreadPool.h"

#ifdef WIN32
#ifdef _DEBUG
#pragma comment(lib, "../lib/ThreadLib_d.lib")
#else
#pragma comment(lib, "../lib/ThreadLib.lib")
#endif
#else
#include <unistd.h>
#endif

class CTest
{
public:
	CTest()
		:m_Thread(NULL)
		,m_bStop(false)
		,m_nThreadParam(5)
		,m_nThreadPoolParam(10)
	{
	}

	~CTest()
	{
		if (m_Thread != NULL)
		{
			delete m_Thread;
			m_Thread = NULL;
		}
	}

	void *ThreadFunc(void* param)
	{
		int *pNum = (int*)param;
		while (!m_bStop)
		{
			printf("\n\tthe param is a number : \"%i\"\n", *pNum);
#ifdef WIN32
			Sleep(500);
#else
			usleep(500*1000);
#endif
		}
		return NULL;
	}

	void *ThreadPoolFunc(void* pParam)
	{
		int *pNum = (int*)pParam;
		while (!m_bStop)
		{
			printf("\n\tThreadPoolFunc Number is : \"%i\"\n", *pNum);
#ifdef WIN32
			Sleep(500);
#else
			usleep(500*1000);
#endif
		}
		return NULL;
	}

	void StartTest()
	{
		if (m_Thread == NULL)
		{
			int *param = &m_nThreadParam;

			m_Thread = new ThreadLib::Thread();
			m_Thread->Run((DWORD)GET_MEMBER_CALLBACK(CTest,ThreadFunc), (DWORD)this, (DWORD)param);
		}

		int *pool = &m_nThreadPoolParam;

		for (int i = 0; i < 2; i++)
			m_ThreadPool.PushTask((DWORD)GET_MEMBER_CALLBACK(CTest,ThreadPoolFunc), (DWORD)this, (DWORD)pool);

		m_ThreadPool.Start(2);
	}

	void StopTest()
	{
		m_bStop = true;
		m_ThreadPool.Stop();
	}

	ThreadLib::Thread *m_Thread;
	ThreadLib::ThreadPool m_ThreadPool;
	bool m_bStop;
	int	m_nThreadParam;
	int	m_nThreadPoolParam;
};

int main(int argc, char* argv[])
{
	CTest a;
	a.StartTest();
	getchar();
	a.StopTest();

	return 0;
}

<commit_msg>更新demo<commit_after>// demo.cpp : ̨Ӧóڵ㡣
//

#include <stdio.h>
#include <assert.h>
#include <map>
#include <vector>

#ifdef WIN32
#include <Windows.h>
#ifdef _DEBUG
#pragma comment(lib, "../lib/ThreadLib_d.lib")
#else
#pragma comment(lib, "../lib/ThreadLib.lib")
#endif
#else
#include <unistd.h>
#endif

#include "CodeAddress.h"
#include "ThreadPool.h"

class CTest
{
public:
	CTest()
		:m_Thread(NULL)
		,m_bStop(false)
		,m_nThreadParam(5)
		,m_nThreadPoolParam(10)
	{
	}

	~CTest()
	{
		if (m_Thread != NULL)
		{
			delete m_Thread;
			m_Thread = NULL;
		}
	}

	void *ThreadFunc(void* param)
	{
		int *pNum = (int*)param;

		while (true)
		{
			bool bRet = m_Event.WaitEvent(1000);
			if (bRet)
			{
				printf("\n\t thread func break\n");
				break;
			}else{
				printf("\n\tthe param is a number : \"%i\"\n", *pNum);
			}
		}
		return NULL;
	}

	void *ThreadPoolFunc(void* pParam)
	{
		int *pNum = (int*)pParam;

		{
			printf("\n\tThreadPoolFunc Number is : \"%i\"\n", *pNum);
		}

		return NULL;
	}

	void StartTest()
	{
		if (m_Thread == NULL)
		{
			int *param = &m_nThreadParam;

			m_Thread = new ThreadLib::Thread();
			m_Thread->Run((DWORD)GET_MEMBER_CALLBACK(CTest,ThreadFunc), (DWORD)this, (DWORD)param);
		}

		int *pool = &m_nThreadPoolParam;

		for (int i = 0; i < 2; i++)
			m_ThreadPool.PushTask((DWORD)GET_MEMBER_CALLBACK(CTest,ThreadPoolFunc), (DWORD)this, (DWORD)pool);

		m_ThreadPool.Start(2);
	}

	void StopTest()
	{
		m_bStop = true;
		m_Event.Set();
		m_ThreadPool.Stop();
	}

	ThreadLib::Thread *m_Thread;
	ThreadLib::ThreadPool m_ThreadPool;
	ThreadLib::Event	m_Event;
	bool m_bStop;
	int	m_nThreadParam;
	int	m_nThreadPoolParam;
};

int main(int argc, char* argv[])
{
	CTest a;
	a.StartTest();
	getchar();
	a.StopTest();

	getchar();
	return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016-2017 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include <QFile>
#include <QHostInfo>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkProxy>
#include <QSysInfo>
#include "de_web_plugin_private.h"
#include "json.h"
#ifdef Q_OS_LINUX
#include <unistd.h>
#endif

/*! Inits the internet discovery manager.
 */
void DeRestPluginPrivate::initInternetDicovery()
{
    Q_ASSERT(inetDiscoveryManager == 0);
    inetDiscoveryManager = new QNetworkAccessManager;
    connect(inetDiscoveryManager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(internetDiscoveryFinishedRequest(QNetworkReply*)));

    DBG_Assert(gwAnnounceInterval >= 0);
    if (gwAnnounceInterval < 0)
    {
        gwAnnounceInterval = 15;
    }

    gwAnnounceVital = 0;
    inetDiscoveryTimer = new QTimer(this);
    inetDiscoveryTimer->setSingleShot(false);

    {
        QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(gwAnnounceUrl));

        if (!proxies.isEmpty())
        {
            const QNetworkProxy &proxy = proxies.first();
            if (proxy.type() == QNetworkProxy::HttpProxy || proxy.type() == QNetworkProxy::HttpCachingProxy)
            {
                gwProxyPort = proxy.port();
                gwProxyAddress = proxy.hostName();
                inetDiscoveryManager->setProxy(proxy);
                QHostInfo::lookupHost(proxy.hostName(),
                                      this, SLOT(inetProxyHostLookupDone(QHostInfo)));
            }
        }
    }

    connect(inetDiscoveryTimer, SIGNAL(timeout()),
            this, SLOT(internetDiscoveryTimerFired()));

    setInternetDiscoveryInterval(gwAnnounceInterval);

    // force first run
    if (gwAnnounceInterval > 0)
    {
        QTimer::singleShot(5000, this, SLOT(internetDiscoveryTimerFired()));
    }

#ifdef Q_OS_LINUX
    // check if we run from shell script
    QFile pproc(QString("/proc/%1/cmdline").arg(getppid()));

    if (pproc.exists() && pproc.open(QIODevice::ReadOnly))
    {

        QByteArray name = pproc.readAll();

        if (name.endsWith(".sh"))
        {
            DBG_Printf(DBG_INFO, "runs in shell script %s\n", qPrintable(name));
            gwRunFromShellScript = true;
        }
        else
        {
            gwRunFromShellScript = false;
            DBG_Printf(DBG_INFO, "parent process %s\n", qPrintable(name));
        }
    }
#else
    gwRunFromShellScript = false;
#endif
    {
        QFile f("/etc/os-release");
        if (f.exists() && f.open(QFile::ReadOnly))
        {
            QTextStream stream(&f);

            while (!stream.atEnd())
            {
                QString line = stream.readLine(200);
                QStringList lineLs = line.split(QChar('='));

                if (lineLs.size() != 2)
                {
                    continue;
                }

                if (lineLs[0] == QLatin1String("PRETTY_NAME"))
                {
                    osPrettyName = lineLs[1];
                    osPrettyName.remove(QChar('"'));
                }
            }
        }
    }
#ifdef ARCH_ARM
    { // get raspberry pi revision
        QFile f("/proc/cpuinfo");
        if (f.exists() && f.open(QFile::ReadOnly))
        {
            QByteArray arr = f.readAll();
            QTextStream stream(arr);

            while (!stream.atEnd())
            {
                QString line = stream.readLine(200);
                QStringList lineLs = line.split(QChar(':'));

                if (lineLs.size() != 2)
                {
                    continue;
                }

                if (lineLs[0].startsWith(QLatin1String("Revision")))
                {
                    piRevision = lineLs[1].trimmed();
                    break;
                }
            }
        }
    }
#endif // ARCH_ARM

    if (osPrettyName.isEmpty())
    {
#ifdef Q_OS_WIN
        switch (QSysInfo::WindowsVersion)
        {
        case QSysInfo::WV_XP:         osPrettyName = QLatin1String("WinXP"); break;
        case QSysInfo::WV_WINDOWS7:   osPrettyName = QLatin1String("Win7"); break;
        case QSysInfo::WV_WINDOWS8:   osPrettyName = QLatin1String("Win8"); break;
        case QSysInfo::WV_WINDOWS8_1: osPrettyName = QLatin1String("Win8.1"); break;
        case QSysInfo::WV_WINDOWS10:  osPrettyName = QLatin1String("Win10"); break;
        default:
            osPrettyName = QLatin1String("Win");
            break;
        }
#endif
#ifdef Q_OS_OSX
        osPrettyName = "Mac";
#endif
#ifdef Q_OS_LINUX
        osPrettyName = "Linux";
#endif
    }
}

/*! Sets the announce interval for internet discovery.

    \param minutes a value between 0..180 min
    \return true on success
 */
bool DeRestPluginPrivate::setInternetDiscoveryInterval(int minutes)
{
    if ((minutes < 0) || (minutes > 180))
    {
        DBG_Printf(DBG_INFO, "discovery ignored invalid announce interval (%d minutes)\n", minutes);
        return false;
    }

    inetDiscoveryTimer->stop();
    gwAnnounceInterval = minutes;

    if (gwAnnounceInterval > 0)
    {
        int msec = 1000 * 60 * gwAnnounceInterval;
        inetDiscoveryTimer->start(msec);
        DBG_Printf(DBG_INFO, "discovery updated announce interval to %d minutes\n", minutes);
    }
    return true;
}

/*! Handle announce trigger timer.
 */
void DeRestPluginPrivate::internetDiscoveryTimerFired()
{
    if (gwAnnounceInterval > 0)
    {
        QString str = QString("{ \"name\": \"%1\", \"mac\": \"%2\", \"internal_ip\":\"%3\", \"internal_port\":%4, \"interval\":%5, \"swversion\":\"%6\", \"fwversion\":\"%7\", \"nodecount\":%8, \"uptime\":%9, \"updatechannel\":\"%10\"")
                .arg(gwName)
                .arg(gwBridgeId)
                .arg(gwConfig["ipaddress"].toString())
                .arg(gwConfig["port"].toDouble())
                .arg(gwAnnounceInterval)
                .arg(gwConfig["swversion"].toString())
                .arg(gwConfig["fwversion"].toString())
                .arg(nodes.size())
                .arg(getUptime())
                .arg(gwUpdateChannel);

        str.append(QString(",\"os\": \"%1\"").arg(osPrettyName));
        if (!piRevision.isEmpty())
        {
            str.append(QString(",\"pirev\": \"%1\"").arg(piRevision));
        }
        str.append(QChar('}'));

        QByteArray data(qPrintable(str));
        inetDiscoveryManager->put(QNetworkRequest(QUrl(gwAnnounceUrl)), data);
    }
}

/*! Callback for finished HTTP requests.

    \param reply the reply to a HTTP request
 */
void DeRestPluginPrivate::internetDiscoveryFinishedRequest(QNetworkReply *reply)
{
    DBG_Assert(reply != 0);

    if (!reply)
    {
        return;
    }

    if (reply->error() == QNetworkReply::NoError)
    {
        DBG_Printf(DBG_INFO, "Announced to internet\n");
#ifdef ARCH_ARM
        // currently this is only supported for the RaspBee Gateway
        internetDiscoveryExtractVersionInfo(reply);
#endif // ARCH_ARM
    }
    else
    {
        DBG_Printf(DBG_INFO, "discovery network reply error: %s\n", qPrintable(reply->errorString()));
    }

    reply->deleteLater();
}

/*! Extracts the update channels version info about the deCONZ/WebApp.

    \param reply which holds the version info in JSON format
 */
void DeRestPluginPrivate::internetDiscoveryExtractVersionInfo(QNetworkReply *reply)
{
    bool ok;
    QByteArray content = reply->readAll();
    QVariant var = Json::parse(content, ok);
    QVariantMap map = var.toMap();

    if (!ok || map.isEmpty())
    {
        DBG_Printf(DBG_ERROR, "discovery couldn't extract version info from reply\n");
    }

    if (map.contains("versions") && (map["versions"].type() == QVariant::Map))
    {
        QString version;
        QVariantMap versions = map["versions"].toMap();

        if (versions.contains(gwUpdateChannel) && (versions[gwUpdateChannel].type() == QVariant::String))
        {
            version = versions[gwUpdateChannel].toString();

            if (!version.isEmpty())
            {
                if (gwUpdateVersion != version)
                {
                    DBG_Printf(DBG_INFO, "discovery found version %s for update channel %s\n", qPrintable(version), qPrintable(gwUpdateChannel));
                    gwUpdateVersion = version;
                    gwSwUpdateState = swUpdateState.readyToInstall;
                    updateEtag(gwConfigEtag);
                }
            }
            else
            {
                DBG_Printf(DBG_ERROR, "discovery reply doesn't contain valid version info for update channel %s\n", qPrintable(gwUpdateChannel));
            }
        }
        else
        {
            DBG_Printf(DBG_ERROR, "discovery reply doesn't contain version info for update channel %s\n", qPrintable(gwUpdateChannel));
        }
    }
    else
    {
        DBG_Printf(DBG_ERROR, "discovery reply doesn't contain valid version info\n");
    }
}

/*! Finished Lookup of http proxy IP address.

    \param host holds the proxy host info
 */
void DeRestPluginPrivate::inetProxyHostLookupDone(const QHostInfo &host)
{
    if (host.error() != QHostInfo::NoError)
    {
        DBG_Printf(DBG_ERROR, "Proxy host lookup failed: %s\n", qPrintable(host.errorString()));
        return;
    }

    foreach (const QHostAddress &address, host.addresses())
    {

        QString addr = address.toString();
        if (address.protocol() == QAbstractSocket::IPv4Protocol &&
            !addr.isEmpty() && gwProxyAddress != address.toString())
        {
            DBG_Printf(DBG_INFO, "Found proxy IP address: %s\n", qPrintable(address.toString()));
            gwProxyAddress = address.toString();
            updateEtag(gwConfigEtag);
            return;
        }
    }
}
<commit_msg>Proxy (2)<commit_after>/*
 * Copyright (c) 2016-2017 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include <QFile>
#include <QHostInfo>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkProxy>
#include <QSysInfo>
#include "de_web_plugin_private.h"
#include "json.h"
#ifdef Q_OS_LINUX
#include <unistd.h>
#endif

/*! Inits the internet discovery manager.
 */
void DeRestPluginPrivate::initInternetDicovery()
{
    Q_ASSERT(inetDiscoveryManager == 0);
    inetDiscoveryManager = new QNetworkAccessManager;
    connect(inetDiscoveryManager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(internetDiscoveryFinishedRequest(QNetworkReply*)));

    DBG_Assert(gwAnnounceInterval >= 0);
    if (gwAnnounceInterval < 0)
    {
        gwAnnounceInterval = 15;
    }

    gwAnnounceVital = 0;
    inetDiscoveryTimer = new QTimer(this);
    inetDiscoveryTimer->setSingleShot(false);

    {
        QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(gwAnnounceUrl));

        if (!proxies.isEmpty())
        {
            const QNetworkProxy &proxy = proxies.first();
            if (proxy.type() == QNetworkProxy::HttpProxy || proxy.type() == QNetworkProxy::HttpCachingProxy)
            {
                gwProxyPort = proxy.port();
                gwProxyAddress = proxy.hostName();
                inetDiscoveryManager->setProxy(proxy);
                QHostInfo::lookupHost(proxy.hostName(),
                                      this, SLOT(inetProxyHostLookupDone(QHostInfo)));
            }
        }
    }

    connect(inetDiscoveryTimer, SIGNAL(timeout()),
            this, SLOT(internetDiscoveryTimerFired()));

    setInternetDiscoveryInterval(gwAnnounceInterval);

    // force first run
    if (gwAnnounceInterval > 0)
    {
        QTimer::singleShot(5000, this, SLOT(internetDiscoveryTimerFired()));
    }

#ifdef Q_OS_LINUX
    // check if we run from shell script
    QFile pproc(QString("/proc/%1/cmdline").arg(getppid()));

    if (pproc.exists() && pproc.open(QIODevice::ReadOnly))
    {

        QByteArray name = pproc.readAll();

        if (name.endsWith(".sh"))
        {
            DBG_Printf(DBG_INFO, "runs in shell script %s\n", qPrintable(name));
            gwRunFromShellScript = true;
        }
        else
        {
            gwRunFromShellScript = false;
            DBG_Printf(DBG_INFO, "parent process %s\n", qPrintable(name));
        }
    }
#else
    gwRunFromShellScript = false;
#endif
    {
        QFile f("/etc/os-release");
        if (f.exists() && f.open(QFile::ReadOnly))
        {
            QTextStream stream(&f);

            while (!stream.atEnd())
            {
                QString line = stream.readLine(200);
                QStringList lineLs = line.split(QChar('='));

                if (lineLs.size() != 2)
                {
                    continue;
                }

                if (lineLs[0] == QLatin1String("PRETTY_NAME"))
                {
                    osPrettyName = lineLs[1];
                    osPrettyName.remove(QChar('"'));
                }
            }
        }
    }
#ifdef ARCH_ARM
    { // get raspberry pi revision
        QFile f("/proc/cpuinfo");
        if (f.exists() && f.open(QFile::ReadOnly))
        {
            QByteArray arr = f.readAll();
            QTextStream stream(arr);

            while (!stream.atEnd())
            {
                QString line = stream.readLine(200);
                QStringList lineLs = line.split(QChar(':'));

                if (lineLs.size() != 2)
                {
                    continue;
                }

                if (lineLs[0].startsWith(QLatin1String("Revision")))
                {
                    piRevision = lineLs[1].trimmed();
                    break;
                }
            }
        }
    }
#endif // ARCH_ARM

    if (osPrettyName.isEmpty())
    {
#ifdef Q_OS_WIN
        switch (QSysInfo::WindowsVersion)
        {
        case QSysInfo::WV_XP:         osPrettyName = QLatin1String("WinXP"); break;
        case QSysInfo::WV_WINDOWS7:   osPrettyName = QLatin1String("Win7"); break;
        case QSysInfo::WV_WINDOWS8:   osPrettyName = QLatin1String("Win8"); break;
        case QSysInfo::WV_WINDOWS8_1: osPrettyName = QLatin1String("Win8.1"); break;
        case QSysInfo::WV_WINDOWS10:  osPrettyName = QLatin1String("Win10"); break;
        default:
            osPrettyName = QLatin1String("Win");
            break;
        }
#endif
#ifdef Q_OS_OSX
        osPrettyName = "Mac";
#endif
#ifdef Q_OS_LINUX
        osPrettyName = "Linux";
#endif
    }
}

/*! Sets the announce interval for internet discovery.

    \param minutes a value between 0..180 min
    \return true on success
 */
bool DeRestPluginPrivate::setInternetDiscoveryInterval(int minutes)
{
    if ((minutes < 0) || (minutes > 180))
    {
        DBG_Printf(DBG_INFO, "discovery ignored invalid announce interval (%d minutes)\n", minutes);
        return false;
    }

    inetDiscoveryTimer->stop();
    gwAnnounceInterval = minutes;

    if (gwAnnounceInterval > 0)
    {
        int msec = 1000 * 60 * gwAnnounceInterval;
        inetDiscoveryTimer->start(msec);
        DBG_Printf(DBG_INFO, "discovery updated announce interval to %d minutes\n", minutes);
    }
    return true;
}

/*! Handle announce trigger timer.
 */
void DeRestPluginPrivate::internetDiscoveryTimerFired()
{
    if (gwAnnounceInterval > 0)
    {
        QString str = QString("{ \"name\": \"%1\", \"mac\": \"%2\", \"internal_ip\":\"%3\", \"internal_port\":%4, \"interval\":%5, \"swversion\":\"%6\", \"fwversion\":\"%7\", \"nodecount\":%8, \"uptime\":%9, \"updatechannel\":\"%10\"")
                .arg(gwName)
                .arg(gwBridgeId)
                .arg(gwConfig["ipaddress"].toString())
                .arg(gwConfig["port"].toDouble())
                .arg(gwAnnounceInterval)
                .arg(gwConfig["swversion"].toString())
                .arg(gwConfig["fwversion"].toString())
                .arg(nodes.size())
                .arg(getUptime())
                .arg(gwUpdateChannel);

        str.append(QString(",\"os\": \"%1\"").arg(osPrettyName));
        if (!piRevision.isEmpty())
        {
            str.append(QString(",\"pirev\": \"%1\"").arg(piRevision));
        }
        str.append(QChar('}'));

        QByteArray data(qPrintable(str));
        inetDiscoveryManager->put(QNetworkRequest(QUrl(gwAnnounceUrl)), data);
    }
}

/*! Callback for finished HTTP requests.

    \param reply the reply to a HTTP request
 */
void DeRestPluginPrivate::internetDiscoveryFinishedRequest(QNetworkReply *reply)
{
    DBG_Assert(reply != 0);

    if (!reply)
    {
        return;
    }

    if (reply->error() == QNetworkReply::NoError)
    {
        if (gwAnnounceVital < 0)
        {
            gwAnnounceVital = 0;
        }
        gwAnnounceVital++;
        DBG_Printf(DBG_INFO, "Announced to internet\n");
#ifdef ARCH_ARM
        // currently this is only supported for the RaspBee Gateway
        internetDiscoveryExtractVersionInfo(reply);
#endif // ARCH_ARM
    }
    else
    {
        DBG_Printf(DBG_INFO, "discovery network reply error: %s\n", qPrintable(reply->errorString()));
        if (gwAnnounceVital > 0)
        {
            gwAnnounceVital = 0;
        }
        gwAnnounceVital--;
    }

    reply->deleteLater();
}

/*! Extracts the update channels version info about the deCONZ/WebApp.

    \param reply which holds the version info in JSON format
 */
void DeRestPluginPrivate::internetDiscoveryExtractVersionInfo(QNetworkReply *reply)
{
    bool ok;
    QByteArray content = reply->readAll();
    QVariant var = Json::parse(content, ok);
    QVariantMap map = var.toMap();

    if (!ok || map.isEmpty())
    {
        DBG_Printf(DBG_ERROR, "discovery couldn't extract version info from reply\n");
    }

    if (map.contains("versions") && (map["versions"].type() == QVariant::Map))
    {
        QString version;
        QVariantMap versions = map["versions"].toMap();

        if (versions.contains(gwUpdateChannel) && (versions[gwUpdateChannel].type() == QVariant::String))
        {
            version = versions[gwUpdateChannel].toString();

            if (!version.isEmpty())
            {
                if (gwUpdateVersion != version)
                {
                    DBG_Printf(DBG_INFO, "discovery found version %s for update channel %s\n", qPrintable(version), qPrintable(gwUpdateChannel));
                    gwUpdateVersion = version;
                    gwSwUpdateState = swUpdateState.readyToInstall;
                    updateEtag(gwConfigEtag);
                }
            }
            else
            {
                DBG_Printf(DBG_ERROR, "discovery reply doesn't contain valid version info for update channel %s\n", qPrintable(gwUpdateChannel));
            }
        }
        else
        {
            DBG_Printf(DBG_ERROR, "discovery reply doesn't contain version info for update channel %s\n", qPrintable(gwUpdateChannel));
        }
    }
    else
    {
        DBG_Printf(DBG_ERROR, "discovery reply doesn't contain valid version info\n");
    }
}

/*! Finished Lookup of http proxy IP address.

    \param host holds the proxy host info
 */
void DeRestPluginPrivate::inetProxyHostLookupDone(const QHostInfo &host)
{
    if (host.error() != QHostInfo::NoError)
    {
        DBG_Printf(DBG_ERROR, "Proxy host lookup failed: %s\n", qPrintable(host.errorString()));
        return;
    }

    foreach (const QHostAddress &address, host.addresses())
    {

        QString addr = address.toString();
        if (address.protocol() == QAbstractSocket::IPv4Protocol &&
            !addr.isEmpty() && gwProxyAddress != address.toString())
        {
            DBG_Printf(DBG_INFO, "Found proxy IP address: %s\n", qPrintable(address.toString()));
            gwProxyAddress = address.toString();
            updateEtag(gwConfigEtag);
            return;
        }
    }
}

/*! Check if a received via field contains a usable proxy.

    \param via holds the proxy host info received by http request header
 */
void DeRestPluginPrivate::inetProxyCheckHttpVia(const QString &via)
{
    if (via.isEmpty())
    {
        return;
    }

    if (gwProxyPort != 0)
    {
        return; // already configured?
    }

    // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.45
    // 1.1 proxy.some-domain.com:3128 (squid/2.7.STABLE9)
    DBG_Printf(DBG_INFO, "Test proxy: \t%s\n", qPrintable(via));

    for (QString &entry : via.split(',')) // there might be multiple proxied in the chain
    {
        QStringList ls = entry.split(' ');
        if (ls.size() < 2)
        {
            continue;
        }

        if (!ls[0].contains(QLatin1String("1.1")))
        {
            continue;
        }

        QStringList recvBy = ls[1].split(':');
        if (ls.size() < 1) // at least host must be specified
        {
            continue;
        }

        quint16 port = 8080;
        if (recvBy.size() == 2) // optional
        {
            port = recvBy[1].toUInt();
        }

        DBG_Printf(DBG_INFO, "\t --> %s:%u\n", qPrintable(recvBy[0]), port);

        if (gwProxyPort != 0)
        {
            continue;
        }

        if (gwAnnounceVital >= 0)
        {
            continue;
        }

        gwProxyAddress = recvBy[0];
        gwProxyPort = port;

        QNetworkProxy proxy(QNetworkProxy::HttpProxy, gwProxyAddress, gwProxyPort);
        inetDiscoveryManager->setProxy(proxy);
        QHostInfo::lookupHost(proxy.hostName(),
                              this, SLOT(inetProxyHostLookupDone(QHostInfo)));
        updateEtag(gwConfigEtag);

        if (gwAnnounceInterval > 0)
        {
            QTimer::singleShot(5000, this, SLOT(internetDiscoveryTimerFired()));
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Sebastien Ronsse

#include "ImGuiHUD.h"
#include "MyImGuiHUD.h"

const struct FKey *KeyMap[] =
{
	&EKeys::Tab,
	&EKeys::Left,
	&EKeys::Right,
	&EKeys::Up,
	&EKeys::Down,
	&EKeys::PageUp,
	&EKeys::PageDown,
	&EKeys::Home,
	&EKeys::End,
	&EKeys::Delete,
	&EKeys::BackSpace,
	&EKeys::Enter,
	&EKeys::Escape,
	&EKeys::A,
	&EKeys::C,
	&EKeys::V,
	&EKeys::X,
	&EKeys::Y,
	&EKeys::Z,
};

AMyImGuiHUD::AMyImGuiHUD() :
	Super(),
	FontTexture(NULL)
{
}

void AMyImGuiHUD::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	// Setup ImGui binding
	ImGui_ImplUE_Init();
}

void AMyImGuiHUD::BeginDestroy()
{
	Super::BeginDestroy();

	// Cleanup
	ImGui_ImplUE_Shutdown();
}

void AMyImGuiHUD::DrawHUD()
{
	// Process events
	ImGui_ImplUE_ProcessEvent();

	// Prepare new frame
	ImGui_ImplUE_NewFrame();

	// Rendering
	ImGui::Render();
}

bool AMyImGuiHUD::ImGui_ImplUE_Init()
{
	ImGuiIO &io = ImGui::GetIO();

	// Keyboard mapping
	for (int i = 0; i < ImGuiKey_COUNT; i++)
		io.KeyMap[i] = i;

	// Fill callbacks
	io.RenderDrawListsFn = ImGui_ImplUE_RenderDrawLists;
	io.SetClipboardTextFn = ImGui_ImplUE_SetClipboardText;
	io.GetClipboardTextFn = ImGui_ImplUE_GetClipboardText;
	io.UserData = this;

	return true;
}

void AMyImGuiHUD::ImGui_ImplUE_Shutdown()
{
	ImGui_ImplUE_InvalidateDeviceObjects();
	ImGui::Shutdown();
}

bool AMyImGuiHUD::ImGui_ImplUE_CreateDeviceObjects()
{
	// Build texture atlas
	ImGuiIO &io = ImGui::GetIO();
	unsigned char *pixels;
	int width, height;
	io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);

	// Upload texture to graphics system
	FontTexture = UTexture2D::CreateTransient(width, height, PF_R8G8B8A8);
	FTexture2DMipMap &mip = FontTexture->PlatformData->Mips[0];
	void *data = mip.BulkData.Lock(LOCK_READ_WRITE);
	FMemory::Memcpy(data, pixels, width * height * 4);
	mip.BulkData.Unlock();
	FontTexture->UpdateResource();

	// Store our identifier
	io.Fonts->TexID = (void *)FontTexture;

	return true;
}

void AMyImGuiHUD::ImGui_ImplUE_InvalidateDeviceObjects()
{
	FontTexture = NULL;
}

void AMyImGuiHUD::ImGui_ImplUE_ProcessEvent()
{
}

void AMyImGuiHUD::ImGui_ImplUE_NewFrame()
{
}

void AMyImGuiHUD::ImGui_ImplUE_RenderDrawLists(ImDrawData *draw_data)
{
}

const char *AMyImGuiHUD::ImGui_ImplUE_GetClipboardText()
{
	return NULL;
}

void AMyImGuiHUD::ImGui_ImplUE_SetClipboardText(const char *text)
{
}
<commit_msg>Filled ImGui frame preparation function<commit_after>// Copyright 2017 Sebastien Ronsse

#include "ImGuiHUD.h"
#include "MyImGuiHUD.h"

const struct FKey *KeyMap[] =
{
	&EKeys::Tab,
	&EKeys::Left,
	&EKeys::Right,
	&EKeys::Up,
	&EKeys::Down,
	&EKeys::PageUp,
	&EKeys::PageDown,
	&EKeys::Home,
	&EKeys::End,
	&EKeys::Delete,
	&EKeys::BackSpace,
	&EKeys::Enter,
	&EKeys::Escape,
	&EKeys::A,
	&EKeys::C,
	&EKeys::V,
	&EKeys::X,
	&EKeys::Y,
	&EKeys::Z,
};

AMyImGuiHUD::AMyImGuiHUD() :
	Super(),
	FontTexture(NULL)
{
}

void AMyImGuiHUD::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	// Setup ImGui binding
	ImGui_ImplUE_Init();
}

void AMyImGuiHUD::BeginDestroy()
{
	Super::BeginDestroy();

	// Cleanup
	ImGui_ImplUE_Shutdown();
}

void AMyImGuiHUD::DrawHUD()
{
	// Process events
	ImGui_ImplUE_ProcessEvent();

	// Prepare new frame
	ImGui_ImplUE_NewFrame();

	// Rendering
	ImGui::Render();
}

bool AMyImGuiHUD::ImGui_ImplUE_Init()
{
	ImGuiIO &io = ImGui::GetIO();

	// Keyboard mapping
	for (int i = 0; i < ImGuiKey_COUNT; i++)
		io.KeyMap[i] = i;

	// Fill callbacks
	io.RenderDrawListsFn = ImGui_ImplUE_RenderDrawLists;
	io.SetClipboardTextFn = ImGui_ImplUE_SetClipboardText;
	io.GetClipboardTextFn = ImGui_ImplUE_GetClipboardText;
	io.UserData = this;

	return true;
}

void AMyImGuiHUD::ImGui_ImplUE_Shutdown()
{
	ImGui_ImplUE_InvalidateDeviceObjects();
	ImGui::Shutdown();
}

bool AMyImGuiHUD::ImGui_ImplUE_CreateDeviceObjects()
{
	// Build texture atlas
	ImGuiIO &io = ImGui::GetIO();
	unsigned char *pixels;
	int width, height;
	io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);

	// Upload texture to graphics system
	FontTexture = UTexture2D::CreateTransient(width, height, PF_R8G8B8A8);
	FTexture2DMipMap &mip = FontTexture->PlatformData->Mips[0];
	void *data = mip.BulkData.Lock(LOCK_READ_WRITE);
	FMemory::Memcpy(data, pixels, width * height * 4);
	mip.BulkData.Unlock();
	FontTexture->UpdateResource();

	// Store our identifier
	io.Fonts->TexID = (void *)FontTexture;

	return true;
}

void AMyImGuiHUD::ImGui_ImplUE_InvalidateDeviceObjects()
{
	FontTexture = NULL;
}

void AMyImGuiHUD::ImGui_ImplUE_ProcessEvent()
{
}

void AMyImGuiHUD::ImGui_ImplUE_NewFrame()
{
	if (!FontTexture)
		ImGui_ImplUE_CreateDeviceObjects();

	ImGuiIO &io = ImGui::GetIO();

	// Setup display size
	io.DisplaySize = ImVec2((float)Canvas->SizeX, (float)Canvas->SizeY);
	io.DisplayFramebufferScale = ImVec2(1, 1);

	// Setup inputs
	APlayerController *pc = GetOwningPlayerController();
	pc->GetMousePosition(io.MousePos.x, io.MousePos.y);
	io.MouseDown[0] = pc->IsInputKeyDown(EKeys::LeftMouseButton);
	io.MouseDown[1] = pc->IsInputKeyDown(EKeys::RightMouseButton);
	io.MouseDown[2] = pc->IsInputKeyDown(EKeys::MiddleMouseButton);

	ImGui::NewFrame();
}

void AMyImGuiHUD::ImGui_ImplUE_RenderDrawLists(ImDrawData *draw_data)
{
}

const char *AMyImGuiHUD::ImGui_ImplUE_GetClipboardText()
{
	return NULL;
}

void AMyImGuiHUD::ImGui_ImplUE_SetClipboardText(const char *text)
{
}
<|endoftext|>


<commit_before>#include <ODLib/ODLib.hpp>
#include <ODLib/Logger/Logger.hpp>

ODLib::Logger::Logger::Logger(ODLib::Logger::Settings Settings)
    : m_settings(Settings)
    , m_nextRotation(GetNextRotation())
{
    CreateFileIfNeeded();
}

ODLib::Logger::Logger::~Logger()
{
    m_file.close();
}

void ODLib::Logger::Logger::WriteLine(const ODLib::Logger::Record::Record& Record)
{
    if (m_settings.DailyRotation == true && std::chrono::system_clock::now() >= m_nextRotation)
    {
        CreateFileIfNeeded();
        m_nextRotation = GetNextRotation();
    }

    auto Result = L"[" + ODLib::Logger::Record::Level::ToString(Record.GetLevel()) + L"] " + Record.GetText();

    std::wcout << Result << std::flush;

    m_file << L"[" << Record.GetTime() << L"] " << Result;
    m_file.flush();
}

void ODLib::Logger::Logger::CreateFileIfNeeded()
{
    if (m_file.is_open() == true)
    {
        m_file.close();
        m_file.clear();
    }

    // Format the time for the file.
    std::wostringstream Result;

    auto Time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    Result << std::put_time(std::localtime(&Time), m_settings.FileName.c_str());

    auto FileName = Result.str();

    // Create the directory if needed.
    std::experimental::filesystem::path Path(FileName);

    auto FileDirectory = Path.parent_path();

    if (FileDirectory.empty() == false && std::experimental::filesystem::exists(FileDirectory) == false)
    {
        std::experimental::filesystem::create_directories(FileDirectory);
    }

    m_file.open(FileName, m_settings.FileMode);

    // Move the input position indicator to the end of the file.
    m_file.seekg(0, std::ios::end);

    // Is the file content empty?
    if (m_file.tellg() > 0)
    {
        // Append a line to separate a the old content from the new content.
        m_file << std::endl;
        m_file << L"-----------------------------------------------------" << std::endl;
    }
}

std::chrono::system_clock::time_point ODLib::Logger::Logger::GetNextRotation()
{
    auto Now = std::chrono::system_clock::now();
    auto Time = std::chrono::system_clock::to_time_t(Now);
    auto Date = std::localtime(&Time);

    // Set midnight time.
    Date->tm_hour = 0;
    Date->tm_min = 0;
    Date->tm_sec = 0;

    // Calculate next rotation.
    auto NextRotation = std::chrono::system_clock::from_time_t(std::mktime(Date));

    if (NextRotation > Now)
    {
        return NextRotation;
    }
    else
    {
        return NextRotation + 24h;
    }
}
<commit_msg>Fix Linux build<commit_after>#include <ODLib/ODLib.hpp>
#include <ODLib/Logger/Logger.hpp>

ODLib::Logger::Logger::Logger(ODLib::Logger::Settings Settings)
    : m_settings(Settings)
    , m_nextRotation(GetNextRotation())
{
    CreateFileIfNeeded();
}

ODLib::Logger::Logger::~Logger()
{
    m_file.close();
}

void ODLib::Logger::Logger::WriteLine(const ODLib::Logger::Record::Record& Record)
{
    if (m_settings.DailyRotation == true && std::chrono::system_clock::now() >= m_nextRotation)
    {
        CreateFileIfNeeded();
        m_nextRotation = GetNextRotation();
    }

    auto Result = L"[" + ODLib::Logger::Record::Level::ToString(Record.GetLevel()) + L"] " + Record.GetText();

    std::wcout << Result << std::flush;

    m_file << L"[" << Record.GetTime() << L"] " << Result;
    m_file.flush();
}

void ODLib::Logger::Logger::CreateFileIfNeeded()
{
    if (m_file.is_open() == true)
    {
        m_file.close();
        m_file.clear();
    }

    // Format the time for the file.
    std::wostringstream Result;

    auto Time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    Result << std::put_time(std::localtime(&Time), m_settings.FileName.c_str());

    auto FileName = Result.str();

    // Create the directory if needed.
    std::experimental::filesystem::path Path(FileName);

    auto FileDirectory = Path.parent_path();

    if (FileDirectory.empty() == false && std::experimental::filesystem::exists(FileDirectory) == false)
    {
        std::experimental::filesystem::create_directories(FileDirectory);
    }

    m_file.open(std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(FileName).c_str(), m_settings.FileMode);

    // Move the input position indicator to the end of the file.
    m_file.seekg(0, std::ios::end);

    // Is the file content empty?
    if (m_file.tellg() > 0)
    {
        // Append a line to separate a the old content from the new content.
        m_file << std::endl;
        m_file << L"-----------------------------------------------------" << std::endl;
    }
}

std::chrono::system_clock::time_point ODLib::Logger::Logger::GetNextRotation()
{
    auto Now = std::chrono::system_clock::now();
    auto Time = std::chrono::system_clock::to_time_t(Now);
    auto Date = std::localtime(&Time);

    // Set midnight time.
    Date->tm_hour = 0;
    Date->tm_min = 0;
    Date->tm_sec = 0;

    // Calculate next rotation.
    auto NextRotation = std::chrono::system_clock::from_time_t(std::mktime(Date));

    if (NextRotation > Now)
    {
        return NextRotation;
    }
    else
    {
        return NextRotation + 24h;
    }
}
<|endoftext|>


<commit_before>#ifndef ITER_FILTER_H_
#define ITER_FILTER_H_

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of Filter and filter
    template <typename FilterFunc, typename Container>
    class Filter;

    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(FilterFunc, Container&&);

    template <typename FilterFunc, typename T>
    Filter<FilterFunc, std::initializer_list<T>> filter(
            FilterFunc, std::initializer_list<T>);

    template <typename FilterFunc, typename Container>
    class Filter {
        private:
            Container container;
            FilterFunc filter_func;

            // The filter function is the only thing allowed to create a Filter
            friend Filter filter<FilterFunc, Container>(
                    FilterFunc, Container&&);

            template <typename FF, typename T>
            friend Filter<FF, std::initializer_list<T>> filter(
                    FF, std::initializer_list<T>);

            // Value constructor for use only in the filter function
            Filter(FilterFunc filter_func, Container container)
                : container(std::forward<Container>(container)),
                filter_func(filter_func)
            { }
            Filter() = delete;
            Filter& operator=(const Filter&) = delete;

        public:
            Filter(const Filter&) = default;

            class Iterator
                : public std::iterator<std::input_iterator_tag,
                        iterator_traits_deref<Container>>
            {
                protected:
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    FilterFunc filter_func;

                    // increment until the iterator points to is true on the
                    // predicate.  Called by constructor and operator++
                    void skip_failures() {
                        while (this->sub_iter != this->sub_end
                                && !this->filter_func(*this->sub_iter)) {
                            ++this->sub_iter;
                        }
                    }

                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            FilterFunc filter_func)
                        : sub_iter{iter},
                        sub_end{end},
                        filter_func(filter_func)
                    {
                        this->skip_failures();
                    }

                    iterator_deref<Container> operator*() {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        this->skip_failures();
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

    };

    // Helper function to instantiate a Filter
    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(
            FilterFunc filter_func, Container&& container) {
        return {filter_func, std::forward<Container>(container)};
    }

    template <typename FilterFunc, typename T>
    Filter<FilterFunc, std::initializer_list<T>> filter(
            FilterFunc filter_func,
            std::initializer_list<T> il)
    {
        return {filter_func, std::move(il)};
    }

    namespace detail {

        template <typename T>
        bool boolean_cast(const T& t) {
            return bool(t);
        }

        template <typename Container>
        class BoolTester {
            public:
                bool operator() (const iterator_deref<Container> item) const {
                    return bool(item);
                }
        };
    }

    template <typename Container>
    auto filter(Container&& container) ->
            decltype(filter(
                        detail::BoolTester<Container>(),
                        std::forward<Container>(container))) {
        return filter(
                detail::BoolTester<Container>(),
                std::forward<Container>(container));
    }

    template <typename T>
    auto filter(std::initializer_list<T> il) ->
            decltype(filter(
                        detail::BoolTester<std::initializer_list<T>>(),
                        std::move(il))) {
           return filter(
                   detail::BoolTester<std::initializer_list<T>>(),
                   std::move(il));
    }

}

#endif // #ifndef ITER_FILTER_H_
<commit_msg>adds filter iter ==<commit_after>#ifndef ITER_FILTER_H_
#define ITER_FILTER_H_

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of Filter and filter
    template <typename FilterFunc, typename Container>
    class Filter;

    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(FilterFunc, Container&&);

    template <typename FilterFunc, typename T>
    Filter<FilterFunc, std::initializer_list<T>> filter(
            FilterFunc, std::initializer_list<T>);

    template <typename FilterFunc, typename Container>
    class Filter {
        private:
            Container container;
            FilterFunc filter_func;

            // The filter function is the only thing allowed to create a Filter
            friend Filter filter<FilterFunc, Container>(
                    FilterFunc, Container&&);

            template <typename FF, typename T>
            friend Filter<FF, std::initializer_list<T>> filter(
                    FF, std::initializer_list<T>);

            // Value constructor for use only in the filter function
            Filter(FilterFunc filter_func, Container container)
                : container(std::forward<Container>(container)),
                filter_func(filter_func)
            { }
            Filter() = delete;
            Filter& operator=(const Filter&) = delete;

        public:
            Filter(const Filter&) = default;

            class Iterator
                : public std::iterator<std::input_iterator_tag,
                        iterator_traits_deref<Container>>
            {
                protected:
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    FilterFunc filter_func;

                    // increment until the iterator points to is true on the
                    // predicate.  Called by constructor and operator++
                    void skip_failures() {
                        while (this->sub_iter != this->sub_end
                                && !this->filter_func(*this->sub_iter)) {
                            ++this->sub_iter;
                        }
                    }

                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            FilterFunc filter_func)
                        : sub_iter{iter},
                        sub_end{end},
                        filter_func(filter_func)
                    {
                        this->skip_failures();
                    }

                    iterator_deref<Container> operator*() {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        this->skip_failures();
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

    };

    // Helper function to instantiate a Filter
    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(
            FilterFunc filter_func, Container&& container) {
        return {filter_func, std::forward<Container>(container)};
    }

    template <typename FilterFunc, typename T>
    Filter<FilterFunc, std::initializer_list<T>> filter(
            FilterFunc filter_func,
            std::initializer_list<T> il)
    {
        return {filter_func, std::move(il)};
    }

    namespace detail {

        template <typename T>
        bool boolean_cast(const T& t) {
            return bool(t);
        }

        template <typename Container>
        class BoolTester {
            public:
                bool operator() (const iterator_deref<Container> item) const {
                    return bool(item);
                }
        };
    }

    template <typename Container>
    auto filter(Container&& container) ->
            decltype(filter(
                        detail::BoolTester<Container>(),
                        std::forward<Container>(container))) {
        return filter(
                detail::BoolTester<Container>(),
                std::forward<Container>(container));
    }

    template <typename T>
    auto filter(std::initializer_list<T> il) ->
            decltype(filter(
                        detail::BoolTester<std::initializer_list<T>>(),
                        std::move(il))) {
           return filter(
                   detail::BoolTester<std::initializer_list<T>>(),
                   std::move(il));
    }

}

#endif // #ifndef ITER_FILTER_H_
<|endoftext|>


<commit_before>//
//  __ParseBridge-Android.cpp
//  roll-eat
//
//  Created by Zinge on 5/16/16.
//
//

#include "ee/internal/MessageBridge.hpp"
#include "ee/JniUtils.hpp"
#include "ee/internal/JniMethodInfo.hpp"
#include "ee/internal/JniString.hpp"
#include "ee/Logger.hpp"

namespace ee {
std::string MessageBridge::call(const std::string& tag,
                                const std::string& msg) {
    auto methodInfo = JniUtils::getStaticMethodInfo(
        "com/ee/core/internal/MessageBridge", "staticCall",
        "(Ljava/lang/String;Ljava/lang/String;");

    if (methodInfo == nullptr) {
        throw std::runtime_error("Method not found!");
    }

    auto tag_java = JniUtils::toJavaString(tag.c_str());
    auto msg_java = JniUtils::toJavaString(msg.c_str());

    jobject response = methodInfo->getEnv()->CallStaticObjectMethod(
        methodInfo->getClass(), methodInfo->getMethodId(), tag_java->get(),
        msg_java->get());

    jstring response_java = static_cast<jstring>(response);
    auto result = JniUtils::toString(response_java);

    methodInfo->getEnv()->DeleteLocalRef(response);

    return result;
}
} // namespace ee
<commit_msg>Fix incorrect JNI call.<commit_after>//
//  __ParseBridge-Android.cpp
//  roll-eat
//
//  Created by Zinge on 5/16/16.
//
//

#include "ee/internal/MessageBridge.hpp"
#include "ee/JniUtils.hpp"
#include "ee/internal/JniMethodInfo.hpp"
#include "ee/internal/JniString.hpp"
#include "ee/Logger.hpp"

namespace ee {
std::string MessageBridge::call(const std::string& tag,
                                const std::string& msg) {
    auto methodInfo = JniUtils::getStaticMethodInfo(
        "com/ee/internal/MessageBridge", "staticCall",
        "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

    if (methodInfo == nullptr) {
        throw std::runtime_error("Method not found!");
    }

    auto tag_java = JniUtils::toJavaString(tag.c_str());
    auto msg_java = JniUtils::toJavaString(msg.c_str());

    jobject response = methodInfo->getEnv()->CallStaticObjectMethod(
        methodInfo->getClass(), methodInfo->getMethodId(), tag_java->get(),
        msg_java->get());

    jstring response_java = static_cast<jstring>(response);
    auto result = JniUtils::toString(response_java);

    methodInfo->getEnv()->DeleteLocalRef(response);

    return result;
}
} // namespace ee
<|endoftext|>