<commit_before>/*
 * Copyright (c) 2012, The University of Oxford
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the University of Oxford nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <cuda_runtime_api.h>

#include "interferometry/oskar_interferometer.h"
#include "interferometry/oskar_correlate.h"
#include "interferometry/oskar_evaluate_jones_K.h"
#include "interferometry/oskar_evaluate_uvw_station.h"
#include "math/oskar_Jones.h"
#include "math/oskar_jones_join.h"
#include "sky/oskar_evaluate_jones_R.h"
#include "sky/oskar_mjd_to_gast_fast.h"
#include "sky/oskar_sky_model_horizon_clip.h"
#include "station/oskar_evaluate_jones_E.h"
#include "utility/oskar_Device_curand_state.h"
#include "utility/oskar_log_message.h"
#include "utility/oskar_log_warning.h"
#include <cstdio>

extern "C"
int oskar_interferometer(oskar_Mem* vis_amp, oskar_Log* log,
        const oskar_SkyModel* sky, const oskar_TelescopeModel* telescope,
        const oskar_Settings* settings, double frequency, int chunk_index,
        int num_sky_chunks)
{
    int err = 0;
    int device_id = 0;
    size_t mem_free = 0, mem_total = 0;
    cudaDeviceProp device_prop;

    cudaGetDevice(&device_id);

    // Check if sky model is empty.
    if (sky->num_sources == 0)
    {
        oskar_log_warning(log, "No sources in sky model. Skipping "
                "Measurement Equation evaluation.");
        return OSKAR_SUCCESS;
    }

    // Copy telescope model and sky model for frequency scaling.
    oskar_TelescopeModel tel_gpu(telescope, OSKAR_LOCATION_GPU);
    oskar_SkyModel sky_gpu(sky, OSKAR_LOCATION_GPU);

    // Scale GPU telescope coordinates by wavenumber.
    err = tel_gpu.multiply_by_wavenumber(frequency);
    if (err) return err;

    // Scale by spectral index.
    err = sky_gpu.scale_by_spectral_index(frequency);
    if (err) return err;

    // Initialise blocks of Jones matrices and visibilities.
    int type = sky_gpu.type();
    int n_stations = tel_gpu.num_stations;
    int n_baselines = n_stations * (n_stations - 1) / 2;
    int n_sources = sky_gpu.num_sources;
    int complex_scalar = type | OSKAR_COMPLEX;
    int complex_matrix = type | OSKAR_COMPLEX | OSKAR_MATRIX;
    oskar_Jones J(complex_matrix, OSKAR_LOCATION_GPU, n_stations, n_sources);
    oskar_Jones R(complex_matrix, OSKAR_LOCATION_GPU, n_stations, n_sources);
    oskar_Jones E(complex_matrix, OSKAR_LOCATION_GPU, n_stations, n_sources);
    oskar_Jones K(complex_scalar, OSKAR_LOCATION_GPU, n_stations, n_sources);
    oskar_Mem vis(complex_matrix, OSKAR_LOCATION_GPU, n_baselines);
    oskar_Mem u(type, OSKAR_LOCATION_GPU, n_stations, true);
    oskar_Mem v(type, OSKAR_LOCATION_GPU, n_stations, true);
    oskar_Mem w(type, OSKAR_LOCATION_GPU, n_stations, true);
    oskar_WorkStationBeam work(type, OSKAR_LOCATION_GPU);

    // Declare a local sky model of sufficient size for the horizon clip.
    oskar_SkyModel local_sky(type, OSKAR_LOCATION_GPU, n_sources);

    // Initialise the random number generator.
    // Note: This is reset to the same sequence per sky chunk and per channel.
    // This is required so that when splitting the sky into chunks or channels
    // antennas still have the same error value for the given time and seed.
    oskar_Device_curand_state curand_state(telescope->max_station_size);
    curand_state.init(telescope->seed_time_variable_station_element_errors);

    // Get time increments.
    int num_vis_dumps        = settings->obs.num_time_steps;
    double obs_start_mjd_utc = settings->obs.start_mjd_utc;
    int num_vis_ave          = settings->interferometer.num_vis_ave;
    int num_fringe_ave       = settings->interferometer.num_fringe_ave;
    double dt_dump   = settings->obs.dt_dump_days;
    double dt_ave    = dt_dump / settings->interferometer.num_vis_ave;
    double dt_fringe = dt_ave / settings->interferometer.num_fringe_ave;

    // Start simulation.
    for (int j = 0; j < num_vis_dumps; ++j)
    {
        // Start time for the visibility dump, in MJD(UTC).
        double t_dump = obs_start_mjd_utc + j * dt_dump;
        double gast = oskar_mjd_to_gast_fast(t_dump + dt_dump / 2.0);

        // Initialise visibilities for the dump to zero.
        err = vis.clear_contents();
        if (err) return err;

        // Compact sky model to temporary.
        err = oskar_sky_model_horizon_clip(&local_sky, &sky_gpu, &tel_gpu,
                gast, &work);

        // Record number of visible sources in this snapshot.
        oskar_log_message(log, 1, "Snapshot %4d/%d, chunk %4d/%d, "
                "device %d [%d sources]", j+1, num_vis_dumps, chunk_index+1,
                num_sky_chunks, device_id, local_sky.num_sources);

        // Skip iteration if no sources above horizon.
        if (err == OSKAR_ERR_NO_VISIBLE_SOURCES) continue;
        else if (err != 0) return err;

        // Set dimensions of Jones matrices (this is not a resize!).
        err = J.set_size(n_stations, local_sky.num_sources); if (err) return err;
        err = R.set_size(n_stations, local_sky.num_sources); if (err) return err;
        err = E.set_size(n_stations, local_sky.num_sources); if (err) return err;
        err = K.set_size(n_stations, local_sky.num_sources); if (err) return err;

        // Average snapshot.
        for (int i = 0; i < num_vis_ave; ++i)
        {
            // Evaluate Greenwich Apparent Sidereal Time.
            double t_ave = t_dump + i * dt_ave;
            double gast = oskar_mjd_to_gast_fast(t_ave + dt_ave / 2);

            // Evaluate parallactic angle rotation (Jones R).
            err = oskar_evaluate_jones_R(&R, &local_sky, &tel_gpu, gast);
            if (err) return err;

            // Evaluate station beam (Jones E).
            err = oskar_evaluate_jones_E(&E, &local_sky, &tel_gpu, gast,
                    &work, &curand_state);
            if (err) return err;

            // Join Jones matrices (R = E * R).
            err = oskar_jones_join(&R, &E, &R);
            if (err) return err;

            for (int k = 0; k < num_fringe_ave; ++k)
            {
                // Evaluate Greenwich Apparent Sidereal Time.
                double t_fringe = t_ave + k * dt_fringe;
                double gast = oskar_mjd_to_gast_fast(t_fringe + dt_fringe / 2);

                // Evaluate station u,v,w coordinates.
                oskar_evaluate_uvw_station(&u, &v, &w, tel_gpu.num_stations,
                        &tel_gpu.station_x, &tel_gpu.station_y,
                        &tel_gpu.station_z, tel_gpu.ra0_rad, tel_gpu.dec0_rad,
                        gast, &err);
                if (err) return err;

                // Evaluate interferometer phase (Jones K).
                err = oskar_evaluate_jones_K(&K, &local_sky, &u, &v, &w);
                if (err) return err;

                // Join Jones matrices (J = K * R).
                err = oskar_jones_join(&J, &K, &R);
                if (err) return err;

                // Form baseline pairs.
                err = oskar_correlate(&vis, &J, &tel_gpu, &local_sky, &u, &v);
                if (err) return err;
            }
        }

        // Divide visibilities by number of averages.
        err = vis.scale_real(1.0 / (num_fringe_ave * num_vis_ave));
        if (err) return err;

        // Add visibilities to global data.
        err = vis_amp->insert(&vis, j * n_baselines);
        if (err) return err;
    }

    // Record GPU memory usage.
    cudaMemGetInfo(&mem_free, &mem_total);
    cudaGetDeviceProperties(&device_prop, device_id);
    oskar_log_message(log, 1, "Memory on device %d [%s] is %.1f%% used.",
            device_id, device_prop.name,
            100.0 * (1.0 - ((double)mem_free / (double)mem_total)));

    return OSKAR_SUCCESS;
}
<commit_msg>Fixed bug: initialised all visibilities to zero in the case where there are no sources above the horizon in the chunk.<commit_after>/*
 * Copyright (c) 2012, The University of Oxford
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the University of Oxford nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <cuda_runtime_api.h>

#include "interferometry/oskar_interferometer.h"
#include "interferometry/oskar_correlate.h"
#include "interferometry/oskar_evaluate_jones_K.h"
#include "interferometry/oskar_evaluate_uvw_station.h"
#include "math/oskar_Jones.h"
#include "math/oskar_jones_join.h"
#include "sky/oskar_evaluate_jones_R.h"
#include "sky/oskar_mjd_to_gast_fast.h"
#include "sky/oskar_sky_model_horizon_clip.h"
#include "station/oskar_evaluate_jones_E.h"
#include "utility/oskar_Device_curand_state.h"
#include "utility/oskar_log_message.h"
#include "utility/oskar_log_warning.h"
#include <cstdio>

extern "C"
int oskar_interferometer(oskar_Mem* vis_amp, oskar_Log* log,
        const oskar_SkyModel* sky, const oskar_TelescopeModel* telescope,
        const oskar_Settings* settings, double frequency, int chunk_index,
        int num_sky_chunks)
{
    int err = 0;
    int device_id = 0;
    size_t mem_free = 0, mem_total = 0;
    cudaDeviceProp device_prop;

    // Always clear the output array to ensure that all visibilities are zero
    // if there are never any visible sources in the sky model.
    err = vis_amp->clear_contents();
    if (err) return err;

    // Get the current device ID.
    cudaGetDevice(&device_id);

    // Check if sky model is empty.
    if (sky->num_sources == 0)
    {
        oskar_log_warning(log, "No sources in sky model. Skipping "
                "Measurement Equation evaluation.");
        return OSKAR_SUCCESS;
    }

    // Copy telescope model and sky model for frequency scaling.
    oskar_TelescopeModel tel_gpu(telescope, OSKAR_LOCATION_GPU);
    oskar_SkyModel sky_gpu(sky, OSKAR_LOCATION_GPU);

    // Scale GPU telescope coordinates by wavenumber.
    err = tel_gpu.multiply_by_wavenumber(frequency);
    if (err) return err;

    // Scale by spectral index.
    err = sky_gpu.scale_by_spectral_index(frequency);
    if (err) return err;

    // Initialise blocks of Jones matrices and visibilities.
    int type = sky_gpu.type();
    int n_stations = tel_gpu.num_stations;
    int n_baselines = n_stations * (n_stations - 1) / 2;
    int n_sources = sky_gpu.num_sources;
    int complex_scalar = type | OSKAR_COMPLEX;
    int complex_matrix = type | OSKAR_COMPLEX | OSKAR_MATRIX;
    oskar_Jones J(complex_matrix, OSKAR_LOCATION_GPU, n_stations, n_sources);
    oskar_Jones R(complex_matrix, OSKAR_LOCATION_GPU, n_stations, n_sources);
    oskar_Jones E(complex_matrix, OSKAR_LOCATION_GPU, n_stations, n_sources);
    oskar_Jones K(complex_scalar, OSKAR_LOCATION_GPU, n_stations, n_sources);
    oskar_Mem vis(complex_matrix, OSKAR_LOCATION_GPU, n_baselines);
    oskar_Mem u(type, OSKAR_LOCATION_GPU, n_stations, true);
    oskar_Mem v(type, OSKAR_LOCATION_GPU, n_stations, true);
    oskar_Mem w(type, OSKAR_LOCATION_GPU, n_stations, true);
    oskar_WorkStationBeam work(type, OSKAR_LOCATION_GPU);

    // Declare a local sky model of sufficient size for the horizon clip.
    oskar_SkyModel local_sky(type, OSKAR_LOCATION_GPU, n_sources);

    // Initialise the random number generator.
    // Note: This is reset to the same sequence per sky chunk and per channel.
    // This is required so that when splitting the sky into chunks or channels
    // antennas still have the same error value for the given time and seed.
    oskar_Device_curand_state curand_state(telescope->max_station_size);
    curand_state.init(telescope->seed_time_variable_station_element_errors);

    // Get time increments.
    int num_vis_dumps        = settings->obs.num_time_steps;
    double obs_start_mjd_utc = settings->obs.start_mjd_utc;
    int num_vis_ave          = settings->interferometer.num_vis_ave;
    int num_fringe_ave       = settings->interferometer.num_fringe_ave;
    double dt_dump   = settings->obs.dt_dump_days;
    double dt_ave    = dt_dump / settings->interferometer.num_vis_ave;
    double dt_fringe = dt_ave / settings->interferometer.num_fringe_ave;

    // Start simulation.
    for (int j = 0; j < num_vis_dumps; ++j)
    {
        // Start time for the visibility dump, in MJD(UTC).
        double t_dump = obs_start_mjd_utc + j * dt_dump;
        double gast = oskar_mjd_to_gast_fast(t_dump + dt_dump / 2.0);

        // Initialise visibilities for the dump to zero.
        err = vis.clear_contents();
        if (err) return err;

        // Compact sky model to temporary.
        err = oskar_sky_model_horizon_clip(&local_sky, &sky_gpu, &tel_gpu,
                gast, &work);

        // Record number of visible sources in this snapshot.
        oskar_log_message(log, 1, "Snapshot %4d/%d, chunk %4d/%d, "
                "device %d [%d sources]", j+1, num_vis_dumps, chunk_index+1,
                num_sky_chunks, device_id, local_sky.num_sources);

        // Skip iteration if no sources above horizon.
        if (err == OSKAR_ERR_NO_VISIBLE_SOURCES) continue;
        else if (err != 0) return err;

        // Set dimensions of Jones matrices (this is not a resize!).
        err = J.set_size(n_stations, local_sky.num_sources); if (err) return err;
        err = R.set_size(n_stations, local_sky.num_sources); if (err) return err;
        err = E.set_size(n_stations, local_sky.num_sources); if (err) return err;
        err = K.set_size(n_stations, local_sky.num_sources); if (err) return err;

        // Average snapshot.
        for (int i = 0; i < num_vis_ave; ++i)
        {
            // Evaluate Greenwich Apparent Sidereal Time.
            double t_ave = t_dump + i * dt_ave;
            double gast = oskar_mjd_to_gast_fast(t_ave + dt_ave / 2);

            // Evaluate parallactic angle rotation (Jones R).
            err = oskar_evaluate_jones_R(&R, &local_sky, &tel_gpu, gast);
            if (err) return err;

            // Evaluate station beam (Jones E).
            err = oskar_evaluate_jones_E(&E, &local_sky, &tel_gpu, gast,
                    &work, &curand_state);
            if (err) return err;

            // Join Jones matrices (R = E * R).
            err = oskar_jones_join(&R, &E, &R);
            if (err) return err;

            for (int k = 0; k < num_fringe_ave; ++k)
            {
                // Evaluate Greenwich Apparent Sidereal Time.
                double t_fringe = t_ave + k * dt_fringe;
                double gast = oskar_mjd_to_gast_fast(t_fringe + dt_fringe / 2);

                // Evaluate station u,v,w coordinates.
                oskar_evaluate_uvw_station(&u, &v, &w, tel_gpu.num_stations,
                        &tel_gpu.station_x, &tel_gpu.station_y,
                        &tel_gpu.station_z, tel_gpu.ra0_rad, tel_gpu.dec0_rad,
                        gast, &err);
                if (err) return err;

                // Evaluate interferometer phase (Jones K).
                err = oskar_evaluate_jones_K(&K, &local_sky, &u, &v, &w);
                if (err) return err;

                // Join Jones matrices (J = K * R).
                err = oskar_jones_join(&J, &K, &R);
                if (err) return err;

                // Form baseline pairs.
                err = oskar_correlate(&vis, &J, &tel_gpu, &local_sky, &u, &v);
                if (err) return err;
            }
        }

        // Divide visibilities by number of averages.
        err = vis.scale_real(1.0 / (num_fringe_ave * num_vis_ave));
        if (err) return err;

        // Add visibilities to global data.
        err = vis_amp->insert(&vis, j * n_baselines);
        if (err) return err;
    }

    // Record GPU memory usage.
    cudaMemGetInfo(&mem_free, &mem_total);
    cudaGetDeviceProperties(&device_prop, device_id);
    oskar_log_message(log, 1, "Memory on device %d [%s] is %.1f%% used.",
            device_id, device_prop.name,
            100.0 * (1.0 - ((double)mem_free / (double)mem_total)));

    return OSKAR_SUCCESS;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include <cling/Interpreter/Interpreter.h>
#include <cling/Interpreter/Value.h>
#include <iostream>
#include <string>
#include <sstream>

///\brief Pass a value from the compiled program into cling, let cling modify it
///  and return the modified value into the compiled program.
int setAndUpdate(int arg, cling::Interpreter& interp) {
   int ret = arg; // The value that will be modified
                  // Update the value of ret by passing it to the interpreter.
   std::ostringstream sstr;
   sstr << "int& ref = *(int*)" << &ret << ';';
   sstr << "ref = ref * ref;";
   interp.process(sstr.str());
   return ret;
}

///\brief A ridiculously complicated way of converting an int to a string.
std::unique_ptr<std::string> stringify(int value, cling::Interpreter& interp) {

   // Declare the function to cling:
   static const std::string codeFunc = R"CODE(
#include <string>
std::string* createAString(const char* str) {
   return new std::string(str);
})CODE";
   interp.declare(codeFunc);

   // Call the function with "runtime" values:
   std::ostringstream sstr;
   sstr << "createAString(\"" << value << "\");";
   cling::Value res; // Will hold the result of the expression evaluation.
   interp.process(sstr.str(), &res);

   // Grab the return value of `createAString()`:
   std::string* resStr = reinterpret_cast<std::string*>(res.getPtr());
   return std::unique_ptr<std::string>(resStr);
}

int main(int argc, const char* const* argv) {
    // Create the Interpreter. LLVMDIR is provided as -D during compilation.
    cling::Interpreter interp(argc, argv, LLVMDIR);

    std::cout << setAndUpdate(17, interp) << '\n';
    std::cout << *stringify(42, interp) << '\n';

    return 0;
}
<commit_msg>Use static_cast; nicer print-out.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include <cling/Interpreter/Interpreter.h>
#include <cling/Interpreter/Value.h>
#include <iostream>
#include <string>
#include <sstream>

///\brief Pass a value from the compiled program into cling, let cling modify it
///  and return the modified value into the compiled program.
int setAndUpdate(int arg, cling::Interpreter& interp) {
   int ret = arg; // The value that will be modified
                  // Update the value of ret by passing it to the interpreter.
   std::ostringstream sstr;
   sstr << "int& ref = *(int*)" << &ret << ';';
   sstr << "ref = ref * ref;";
   interp.process(sstr.str());
   return ret;
}

///\brief A ridiculously complicated way of converting an int to a string.
std::unique_ptr<std::string> stringify(int value, cling::Interpreter& interp) {

   // Declare the function to cling:
   static const std::string codeFunc = R"CODE(
#include <string>
std::string* createAString(const char* str) {
   return new std::string(str);
})CODE";
   interp.declare(codeFunc);

   // Call the function with "runtime" values:
   std::ostringstream sstr;
   sstr << "createAString(\"" << value << "\");";
   cling::Value res; // Will hold the result of the expression evaluation.
   interp.process(sstr.str(), &res);

   // Grab the return value of `createAString()`:
   std::string* resStr = static_cast<std::string*>(res.getPtr());
   return std::unique_ptr<std::string>(resStr);
}

int main(int argc, const char* const* argv) {
    // Create the Interpreter. LLVMDIR is provided as -D during compilation.
    cling::Interpreter interp(argc, argv, LLVMDIR);

    std::cout << "The square of 17 is " << setAndUpdate(17, interp) << '\n';
    std::cout << "Printing a string of 42: " << *stringify(42, interp) << '\n';

    return 0;
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file whisperTopic.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */
#include <functional>
#include <boost/test/unit_test.hpp>
#include <libp2p/Host.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;

BOOST_AUTO_TEST_SUITE(whisper)

BOOST_AUTO_TEST_CASE(topic)
{
	cnote << "Testing Whisper...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	bool started = false;
	unsigned result = 0;
	std::thread listener([&]()
	{
		setThreadName("other");

		Host ph("Test", NetworkPreferences(50303, "", false, true));
		auto wh = ph.registerCapability(new WhisperHost());
		ph.start();

		started = true;

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("odd"));

		for (int i = 0, last = 0; i < 200 && last < 81; ++i)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open();
				last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
				result += last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!started)
		this_thread::sleep_for(chrono::milliseconds(50));

	Host ph("Test", NetworkPreferences(50300, "", false, true));
	auto wh = ph.registerCapability(new WhisperHost());
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.start();
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.connect("127.0.0.1", 50303);

	KeyPair us = KeyPair::create();
	for (int i = 0; i < 10; ++i)
	{
		wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	listener.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Fix jsTo...<commit_after>/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file whisperTopic.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */
#include <functional>
#include <boost/test/unit_test.hpp>
#include <libp2p/Host.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;

BOOST_AUTO_TEST_SUITE(whisper)

BOOST_AUTO_TEST_CASE(topic)
{
	cnote << "Testing Whisper...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	bool started = false;
	unsigned result = 0;
	std::thread listener([&]()
	{
		setThreadName("other");

		Host ph("Test", NetworkPreferences(50303, "", false, true));
		auto wh = ph.registerCapability(new WhisperHost());
		ph.start();

		started = true;

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("odd"));

		for (int i = 0, last = 0; i < 200 && last < 81; ++i)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open();
				last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
				result += last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!started)
		this_thread::sleep_for(chrono::milliseconds(50));

	Host ph("Test", NetworkPreferences(50300, "", false, true));
	shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.start();
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.connect("127.0.0.1", 50303);

	KeyPair us = KeyPair::create();
	for (int i = 0; i < 10; ++i)
	{
		wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	listener.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file whisperTopic.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */
#include <functional>
#include <boost/test/unit_test.hpp>
#include <libp2p/Host.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;

BOOST_AUTO_TEST_SUITE(whisper)

BOOST_AUTO_TEST_CASE(topic)
{
	cnote << "Testing Whisper...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	bool started = false;
	unsigned result = 0;
	std::thread listener([&]()
	{
		setThreadName("other");

		Host ph("Test", NetworkPreferences(50303, "", false, true));
		auto wh = ph.registerCapability(new WhisperHost());
		ph.start();

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("odd"));

		started = true;

		for (int iterout = 0, last = 0; iterout < 200 && last < 81; ++iterout)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
				result += last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!started)
		this_thread::sleep_for(chrono::milliseconds(50));

	Host ph("Test", NetworkPreferences(50300, "", false, true));
	shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.start();
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.connect("127.0.0.1", 50303);

	KeyPair us = KeyPair::create();
	for (int i = 0; i < 10; ++i)
	{
		wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	listener.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
}

BOOST_AUTO_TEST_CASE(forwarding)
{
	cnote << "Testing Whisper forwarding...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	unsigned result = 0;
	bool done = false;

	bool startedListener = false;
	std::thread listener([&]()
	{
		setThreadName("listener");

		// Host must be configured not to share peers.
		Host ph("Listner", NetworkPreferences(50303, "", false, true));
		ph.setIdealPeerCount(0);
		auto wh = ph.registerCapability(new WhisperHost());
		ph.start();

		startedListener = true;

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		for (int i = 0; i < 200 && !result; ++i)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				unsigned last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
				result = last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	bool startedForwarder = false;
	std::thread forwarder([&]()
	{
		setThreadName("forwarder");

		while (!startedListener)
			this_thread::sleep_for(chrono::milliseconds(50));

		// Host must be configured not to share peers.
		Host ph("Forwarder", NetworkPreferences(50305, "", false, true));
		ph.setIdealPeerCount(0);
		auto wh = ph.registerCapability(new WhisperHost());
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.start();

		this_thread::sleep_for(chrono::milliseconds(500));
		ph.connect("127.0.0.1", 50303);

		startedForwarder = true;

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		while (!done)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!startedForwarder)
		this_thread::sleep_for(chrono::milliseconds(50));

	Host ph("Sender", NetworkPreferences(50300, "", false, true));
	ph.setIdealPeerCount(0);
	shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.start();
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.connect("127.0.0.1", 50305);

	KeyPair us = KeyPair::create();
	wh->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
	this_thread::sleep_for(chrono::milliseconds(250));

	listener.join();
	done = true;
	forwarder.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1);
}

BOOST_AUTO_TEST_CASE(asyncforwarding)
{
	cnote << "Testing Whisper async forwarding...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 2;

	unsigned result = 0;
	bool done = false;

	bool startedForwarder = false;
	std::thread forwarder([&]()
	{
		setThreadName("forwarder");

		// Host must be configured not to share peers.
		Host ph("Forwarder", NetworkPreferences(50305, "", false, true));
		ph.setIdealPeerCount(0);
		auto wh = ph.registerCapability(new WhisperHost());
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.start();

		this_thread::sleep_for(chrono::milliseconds(500));
		ph.connect("127.0.0.1", 50303);

		startedForwarder = true;

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		while (!done)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!startedForwarder)
		this_thread::sleep_for(chrono::milliseconds(50));

	{
		Host ph("Sender", NetworkPreferences(50300, "", false, true));
		ph.setIdealPeerCount(0);
		shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.start();
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.connect("127.0.0.1", 50305);

		KeyPair us = KeyPair::create();
		wh->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	{
		Host ph("Listener", NetworkPreferences(50300, "", false, true));
		ph.setIdealPeerCount(0);
		shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.start();
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.connect("127.0.0.1", 50305);

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		for (int i = 0; i < 200 && !result; ++i)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				unsigned last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
				result = last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	}

	done = true;
	forwarder.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Don't count same messages twice.<commit_after>/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file whisperTopic.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */
#include <functional>
#include <boost/test/unit_test.hpp>
#include <libp2p/Host.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;

BOOST_AUTO_TEST_SUITE(whisper)

BOOST_AUTO_TEST_CASE(topic)
{
	cnote << "Testing Whisper...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	bool started = false;
	unsigned result = 0;
	std::thread listener([&]()
	{
		setThreadName("other");

		Host ph("Test", NetworkPreferences(50303, "", false, true));
		auto wh = ph.registerCapability(new WhisperHost());
		ph.start();

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("odd"));

		started = true;
		set<unsigned> received;

		for (int iterout = 0, last = 0; iterout < 200 && last < 81; ++iterout)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				last = RLP(msg.payload()).toInt<unsigned>();
				if (received.count(last))
					continue;
				received.insert(last);
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
				result += last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!started)
		this_thread::sleep_for(chrono::milliseconds(50));

	Host ph("Test", NetworkPreferences(50300, "", false, true));
	shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.start();
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.connect("127.0.0.1", 50303);

	KeyPair us = KeyPair::create();
	for (int i = 0; i < 10; ++i)
	{
		wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	listener.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
}

BOOST_AUTO_TEST_CASE(forwarding)
{
	cnote << "Testing Whisper forwarding...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	unsigned result = 0;
	bool done = false;

	bool startedListener = false;
	std::thread listener([&]()
	{
		setThreadName("listener");

		// Host must be configured not to share peers.
		Host ph("Listner", NetworkPreferences(50303, "", false, true));
		ph.setIdealPeerCount(0);
		auto wh = ph.registerCapability(new WhisperHost());
		ph.start();

		startedListener = true;

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		for (int i = 0; i < 200 && !result; ++i)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				unsigned last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
				result = last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	bool startedForwarder = false;
	std::thread forwarder([&]()
	{
		setThreadName("forwarder");

		while (!startedListener)
			this_thread::sleep_for(chrono::milliseconds(50));

		// Host must be configured not to share peers.
		Host ph("Forwarder", NetworkPreferences(50305, "", false, true));
		ph.setIdealPeerCount(0);
		auto wh = ph.registerCapability(new WhisperHost());
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.start();

		this_thread::sleep_for(chrono::milliseconds(500));
		ph.connect("127.0.0.1", 50303);

		startedForwarder = true;

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		while (!done)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!startedForwarder)
		this_thread::sleep_for(chrono::milliseconds(50));

	Host ph("Sender", NetworkPreferences(50300, "", false, true));
	ph.setIdealPeerCount(0);
	shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.start();
	this_thread::sleep_for(chrono::milliseconds(500));
	ph.connect("127.0.0.1", 50305);

	KeyPair us = KeyPair::create();
	wh->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
	this_thread::sleep_for(chrono::milliseconds(250));

	listener.join();
	done = true;
	forwarder.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1);
}

BOOST_AUTO_TEST_CASE(asyncforwarding)
{
	cnote << "Testing Whisper async forwarding...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 2;

	unsigned result = 0;
	bool done = false;

	bool startedForwarder = false;
	std::thread forwarder([&]()
	{
		setThreadName("forwarder");

		// Host must be configured not to share peers.
		Host ph("Forwarder", NetworkPreferences(50305, "", false, true));
		ph.setIdealPeerCount(0);
		auto wh = ph.registerCapability(new WhisperHost());
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.start();

		this_thread::sleep_for(chrono::milliseconds(500));
		ph.connect("127.0.0.1", 50303);

		startedForwarder = true;

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		while (!done)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!startedForwarder)
		this_thread::sleep_for(chrono::milliseconds(50));

	{
		Host ph("Sender", NetworkPreferences(50300, "", false, true));
		ph.setIdealPeerCount(0);
		shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.start();
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.connect("127.0.0.1", 50305);

		KeyPair us = KeyPair::create();
		wh->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	{
		Host ph("Listener", NetworkPreferences(50300, "", false, true));
		ph.setIdealPeerCount(0);
		shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.start();
		this_thread::sleep_for(chrono::milliseconds(500));
		ph.connect("127.0.0.1", 50305);

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		for (int i = 0; i < 200 && !result; ++i)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				unsigned last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
				result = last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	}

	done = true;
	forwarder.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "../include/windows/View.h"

// view constructor
View::View(Model* m, int x, int y, int w, int h, const char *label) :
	RenderWindow(x,y,w,h) {

	// set OSG viewport
    this->getCamera()->setViewport(new osg::Viewport(0,0,w,h));

    // get the graphics context
    this->getCamera()->setGraphicsContext(this->getGraphicsWindow());

    // do single-threaded view
   this->setThreadingModel(osgViewer::Viewer::SingleThreaded);

   // set the model
   this->model = m;

   // initialize the root node
   this->root = new osg::Group();

   // initialize the ground
   this->ground = new Ground( 400.0f );

   // add the ground to the root node
   this->root->addChild( this->ground.get() );

	// set the key modifiers to false
   this->modifiers = map< int, bool >();
   this->modifiers[ FL_SHIFT ] = false;
   this->modifiers[ FL_CTRL ] = false;
   this->modifiers[ FL_ALT ] = false;
   this->modifiers[ FL_META ] = false;

   // set up the object map
   this->objectMap = map< bz2object*, osg::ref_ptr< Renderable > >();

	// build the scene from the model
	vector<bz2object*> objects = this->model->getObjects();
	if(objects.size() > 0) {
		for(vector<bz2object*>::iterator i = objects.begin(); i != objects.end(); i++) {
			osg::ref_ptr< Renderable > r = (*i)->makeRenderable();
			bool result = this->root->addChild( r.get() );
			if(result)
				this->objectMap[ *i ] = r;
		}
	}

   // make a new selection object
   this->selection = new Selection();

	// add the root node to the scene
   this->setSceneData( this->root.get() );

   // give the View a trackball manipulator
   osgGA::TrackballManipulator* cameraManipulator = new osgGA::TrackballManipulator();

   this->setCameraManipulator(cameraManipulator);

   // make an event handler collection
   this->eventHandlers = new EventHandlerCollection( this );

   // add the selectHandler
   this->eventHandlers->addEventHandler( selectHandler::getName().c_str(), new selectHandler( this, cameraManipulator ) );

   // add the scene picker event handler
   this->addEventHandler(eventHandlers.get());

}

// destructor
View::~View() { }

// draw method (really simple)
void View::draw(void) {
	this->frame();
}

// handle events
int View::handle(int event) {
	// whatever the event was, we need to regenerate the modifier keys
	int shiftState = Fl::event_state();
	this->modifiers[ FL_SHIFT ] = ( shiftState & FL_SHIFT );
	this->modifiers[ FL_CTRL ] = ( shiftState & FL_CTRL );
	this->modifiers[ FL_META ] = ( shiftState & FL_META );
	this->modifiers[ FL_ALT ] = ( shiftState & FL_ALT );

	this->keydown = Fl::event_key();
	this->buttondown = Fl::event_button();

	// forward FLTK events to OSG
	switch(event){
        case FL_PUSH:
        	// handle single mouse clicks
        	if(Fl::event_clicks() == 0) {
        		_gw->getEventQueue()->mouseButtonPress(Fl::event_x(), Fl::event_y(), Fl::event_button() );
        	}
        	// handle double clicks
            else {
            	_gw->getEventQueue()->mouseDoubleButtonPress(Fl::event_x(), Fl::event_y(), Fl::event_button() );
            	Fl::event_is_click(0);
            }

            this->redraw();
            return 1;

        case FL_DRAG:
        	_gw->getEventQueue()->mouseMotion(Fl::event_x(), Fl::event_y());
        	this->redraw();
			return 1;
        case FL_RELEASE:
            _gw->getEventQueue()->mouseButtonRelease(Fl::event_x(), Fl::event_y(), Fl::event_button() );
        	this->redraw();
			return 1;
        case FL_KEYDOWN:
            _gw->getEventQueue()->keyPress((osgGA::GUIEventAdapter::KeySymbol)Fl::event_key());
            this->redraw();
            return 1;
        case FL_KEYUP:
            _gw->getEventQueue()->keyRelease((osgGA::GUIEventAdapter::KeySymbol)Fl::event_key());
            this->redraw();
            return 1;
        default:
            // pass other events to the base class
            return RenderWindow::handle(event);
    }
}

// update method (inherited from Observer)
void View::update( Observable* obs, void* data ) {
	// if data is not NULL, then we passed in an object to be updated
	if(data != NULL) {
		// get the bz2object
		bz2object* obj = (bz2object*)(data);

		// see if there is a renderable for this object
		if( this->objectMap.count( obj ) > 0 ) {
			// if so, update it (i.e. rebuild it)
			this->root->removeChild( objectMap[ obj ].get() );
			this->objectMap[ obj ] = obj->makeRenderable();
			this->root->addChild( objectMap[ obj ].get() );
		}
	}

	// see if there is nothing selected (if so, make sure the selector isn't present)
	if( this->model->getSelection().size() <= 0 && this->root->containsNode( selection.get() ) )
		this->root->removeChild( selection.get() );

	// refresh the scene
	this->redraw();
}

// is a button pressed?
bool View::isPressed( int value ) {
	return this->modifiers[ value ];
}

// is an object selected?
bool View::isSelected( Renderable* transformedNode ) {
	// a non-existant node isn't selected
	if(transformedNode == NULL)
		return false;

	return this->model->isSelected(transformedNode->getBZWObject());
}
/**
 * Set an object as selected (i.e. tints it green)
 */
void View::setSelected( bz2object* object ) {

	// tell the model that this object is to be selected
	model->setSelected( object );

	// add the selection if it isn't there.
	if( !this->root->containsNode( this->selection.get() ) ) {
		this->root->insertChild( this->root->getNumChildren(), this->selection.get() );
	}

	// update our graphical selection
	selection->add( objectMap[ object ].get() );

}
void View::setSelected( Renderable* object ) {

	if( object->getBZWObject() != NULL )
		this->setSelected( object->getBZWObject() );

}

/**
 * This method does the same as setSelected, but instead of doing the selection, it undoes it.
 */
void View::setUnselected( bz2object* object ) {

	// tell the model that this is unselected
	model->setUnselected( object );

	// remove it from our graphical selection
	selection->remove( objectMap[ object ].get() );

	// disable the 3D cursor if there are no selected objects
	if( selection->getSelection().size() <= 0 )
		this->root->removeChild( selection.get() );

}
void View::setUnselected( Renderable* object ) {

	if( object->getBZWObject() != NULL )
		this->setUnselected( object->getBZWObject() );
}

// mark all nodes unselected
void View::unselectAll() {
	this->model->unselectAll();

	selection->removeAll();

	this->root->removeChild( selection.get() );
}

// tell the model to regenerate a bz2object from the renderable
void View::refresh( Renderable* r ) {
	if(r->getBZWObject() != NULL) {
		r->getBZWObject()->updateRenderable( r );
	}
}
<commit_msg>more implicit casts to bool<commit_after>#include "../include/windows/View.h"

// view constructor
View::View(Model* m, int x, int y, int w, int h, const char *label) :
	RenderWindow(x,y,w,h) {

	// set OSG viewport
    this->getCamera()->setViewport(new osg::Viewport(0,0,w,h));

    // get the graphics context
    this->getCamera()->setGraphicsContext(this->getGraphicsWindow());

    // do single-threaded view
   this->setThreadingModel(osgViewer::Viewer::SingleThreaded);

   // set the model
   this->model = m;

   // initialize the root node
   this->root = new osg::Group();

   // initialize the ground
   this->ground = new Ground( 400.0f );

   // add the ground to the root node
   this->root->addChild( this->ground.get() );

	// set the key modifiers to false
   this->modifiers = map< int, bool >();
   this->modifiers[ FL_SHIFT ] = false;
   this->modifiers[ FL_CTRL ] = false;
   this->modifiers[ FL_ALT ] = false;
   this->modifiers[ FL_META ] = false;

   // set up the object map
   this->objectMap = map< bz2object*, osg::ref_ptr< Renderable > >();

	// build the scene from the model
	vector<bz2object*> objects = this->model->getObjects();
	if(objects.size() > 0) {
		for(vector<bz2object*>::iterator i = objects.begin(); i != objects.end(); i++) {
			osg::ref_ptr< Renderable > r = (*i)->makeRenderable();
			bool result = this->root->addChild( r.get() );
			if(result)
				this->objectMap[ *i ] = r;
		}
	}

   // make a new selection object
   this->selection = new Selection();

	// add the root node to the scene
   this->setSceneData( this->root.get() );

   // give the View a trackball manipulator
   osgGA::TrackballManipulator* cameraManipulator = new osgGA::TrackballManipulator();

   this->setCameraManipulator(cameraManipulator);

   // make an event handler collection
   this->eventHandlers = new EventHandlerCollection( this );

   // add the selectHandler
   this->eventHandlers->addEventHandler( selectHandler::getName().c_str(), new selectHandler( this, cameraManipulator ) );

   // add the scene picker event handler
   this->addEventHandler(eventHandlers.get());

}

// destructor
View::~View() { }

// draw method (really simple)
void View::draw(void) {
	this->frame();
}

// handle events
int View::handle(int event) {
	// whatever the event was, we need to regenerate the modifier keys
	int shiftState = Fl::event_state();
	this->modifiers[ FL_SHIFT ] = (( shiftState & FL_SHIFT ) != 0);
	this->modifiers[ FL_CTRL ] = (( shiftState & FL_CTRL ) != 0);
	this->modifiers[ FL_META ] = (( shiftState & FL_META ) != 0);
	this->modifiers[ FL_ALT ] = (( shiftState & FL_ALT ) != 0);

	this->keydown = Fl::event_key();
	this->buttondown = Fl::event_button();

	// forward FLTK events to OSG
	switch(event){
        case FL_PUSH:
        	// handle single mouse clicks
        	if(Fl::event_clicks() == 0) {
        		_gw->getEventQueue()->mouseButtonPress(Fl::event_x(), Fl::event_y(), Fl::event_button() );
        	}
        	// handle double clicks
            else {
            	_gw->getEventQueue()->mouseDoubleButtonPress(Fl::event_x(), Fl::event_y(), Fl::event_button() );
            	Fl::event_is_click(0);
            }

            this->redraw();
            return 1;

        case FL_DRAG:
        	_gw->getEventQueue()->mouseMotion(Fl::event_x(), Fl::event_y());
        	this->redraw();
			return 1;
        case FL_RELEASE:
            _gw->getEventQueue()->mouseButtonRelease(Fl::event_x(), Fl::event_y(), Fl::event_button() );
        	this->redraw();
			return 1;
        case FL_KEYDOWN:
            _gw->getEventQueue()->keyPress((osgGA::GUIEventAdapter::KeySymbol)Fl::event_key());
            this->redraw();
            return 1;
        case FL_KEYUP:
            _gw->getEventQueue()->keyRelease((osgGA::GUIEventAdapter::KeySymbol)Fl::event_key());
            this->redraw();
            return 1;
        default:
            // pass other events to the base class
            return RenderWindow::handle(event);
    }
}

// update method (inherited from Observer)
void View::update( Observable* obs, void* data ) {
	// if data is not NULL, then we passed in an object to be updated
	if(data != NULL) {
		// get the bz2object
		bz2object* obj = (bz2object*)(data);

		// see if there is a renderable for this object
		if( this->objectMap.count( obj ) > 0 ) {
			// if so, update it (i.e. rebuild it)
			this->root->removeChild( objectMap[ obj ].get() );
			this->objectMap[ obj ] = obj->makeRenderable();
			this->root->addChild( objectMap[ obj ].get() );
		}
	}

	// see if there is nothing selected (if so, make sure the selector isn't present)
	if( this->model->getSelection().size() <= 0 && this->root->containsNode( selection.get() ) )
		this->root->removeChild( selection.get() );

	// refresh the scene
	this->redraw();
}

// is a button pressed?
bool View::isPressed( int value ) {
	return this->modifiers[ value ];
}

// is an object selected?
bool View::isSelected( Renderable* transformedNode ) {
	// a non-existant node isn't selected
	if(transformedNode == NULL)
		return false;

	return this->model->isSelected(transformedNode->getBZWObject());
}
/**
 * Set an object as selected (i.e. tints it green)
 */
void View::setSelected( bz2object* object ) {

	// tell the model that this object is to be selected
	model->setSelected( object );

	// add the selection if it isn't there.
	if( !this->root->containsNode( this->selection.get() ) ) {
		this->root->insertChild( this->root->getNumChildren(), this->selection.get() );
	}

	// update our graphical selection
	selection->add( objectMap[ object ].get() );

}
void View::setSelected( Renderable* object ) {

	if( object->getBZWObject() != NULL )
		this->setSelected( object->getBZWObject() );

}

/**
 * This method does the same as setSelected, but instead of doing the selection, it undoes it.
 */
void View::setUnselected( bz2object* object ) {

	// tell the model that this is unselected
	model->setUnselected( object );

	// remove it from our graphical selection
	selection->remove( objectMap[ object ].get() );

	// disable the 3D cursor if there are no selected objects
	if( selection->getSelection().size() <= 0 )
		this->root->removeChild( selection.get() );

}
void View::setUnselected( Renderable* object ) {

	if( object->getBZWObject() != NULL )
		this->setUnselected( object->getBZWObject() );
}

// mark all nodes unselected
void View::unselectAll() {
	this->model->unselectAll();

	selection->removeAll();

	this->root->removeChild( selection.get() );
}

// tell the model to regenerate a bz2object from the renderable
void View::refresh( Renderable* r ) {
	if(r->getBZWObject() != NULL) {
		r->getBZWObject()->updateRenderable( r );
	}
}
<|endoftext|>


<commit_before>//===-- sanitizer_linux.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements linux-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//
#ifdef __linux__

#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_procmaps.h"

#include <fcntl.h>
#include <pthread.h>
#include <sched.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

namespace __sanitizer {

// --------------- sanitizer_libc.h
void *internal_mmap(void *addr, uptr length, int prot, int flags,
                    int fd, u64 offset) {
#if __WORDSIZE == 64
  return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
#else
  return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
#endif
}

int internal_munmap(void *addr, uptr length) {
  return syscall(__NR_munmap, addr, length);
}

int internal_close(fd_t fd) {
  return syscall(__NR_close, fd);
}

fd_t internal_open(const char *filename, bool write) {
  return syscall(__NR_open, filename,
      write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
}

uptr internal_read(fd_t fd, void *buf, uptr count) {
  return (uptr)syscall(__NR_read, fd, buf, count);
}

uptr internal_write(fd_t fd, const void *buf, uptr count) {
  return (uptr)syscall(__NR_write, fd, buf, count);
}

uptr internal_filesize(fd_t fd) {
  struct stat st = {};
  if (syscall(__NR_fstat, fd, &st))
    return -1;
  return (uptr)st.st_size;
}

int internal_dup2(int oldfd, int newfd) {
  return syscall(__NR_dup2, oldfd, newfd);
}

int internal_sched_yield() {
  return syscall(__NR_sched_yield);
}

// ----------------- sanitizer_common.h
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                uptr *stack_bottom) {
  static const uptr kMaxThreadStackSize = 256 * (1 << 20);  // 256M
  CHECK(stack_top);
  CHECK(stack_bottom);
  if (at_initialization) {
    // This is the main thread. Libpthread may not be initialized yet.
    struct rlimit rl;
    CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);

    // Find the mapping that contains a stack variable.
    ProcessMaps proc_maps;
    uptr start, end, offset;
    uptr prev_end = 0;
    while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
      if ((uptr)&rl < end)
        break;
      prev_end = end;
    }
    CHECK((uptr)&rl >= start && (uptr)&rl < end);

    // Get stacksize from rlimit, but clip it so that it does not overlap
    // with other mappings.
    uptr stacksize = rl.rlim_cur;
    if (stacksize > end - prev_end)
      stacksize = end - prev_end;
    // When running with unlimited stack size, we still want to set some limit.
    // The unlimited stack size is caused by 'ulimit -s unlimited'.
    // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
    if (stacksize > kMaxThreadStackSize)
      stacksize = kMaxThreadStackSize;
    *stack_top = end;
    *stack_bottom = end - stacksize;
    return;
  }
  pthread_attr_t attr;
  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
  uptr stacksize = 0;
  void *stackaddr = 0;
  pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
  pthread_attr_destroy(&attr);

  *stack_top = (uptr)stackaddr + stacksize;
  *stack_bottom = (uptr)stackaddr;
  CHECK(stacksize < kMaxThreadStackSize);  // Sanity check.
}

// Like getenv, but reads env directly from /proc and does not use libc.
// This function should be called first inside __asan_init.
const char *GetEnv(const char *name) {
  static char *environ;
  static uptr len;
  static bool inited;
  if (!inited) {
    inited = true;
    uptr environ_size;
    len = ReadFileToBuffer("/proc/self/environ",
                           &environ, &environ_size, 1 << 26);
  }
  if (!environ || len == 0) return 0;
  uptr namelen = internal_strlen(name);
  const char *p = environ;
  while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
    // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
    const char* endp =
        (char*)internal_memchr(p, '\0', len - (p - environ));
    if (endp == 0)  // this entry isn't NUL terminated
      return 0;
    else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
      return p + namelen + 1;  // point after =
    p = endp + 1;
  }
  return 0;  // Not found.
}

// ----------------- sanitizer_procmaps.h
ProcessMaps::ProcessMaps() {
  proc_self_maps_buff_len_ =
      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
                       &proc_self_maps_buff_mmaped_size_, 1 << 26);
  CHECK_GT(proc_self_maps_buff_len_, 0);
  // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
  Reset();
}

ProcessMaps::~ProcessMaps() {
  UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
}

void ProcessMaps::Reset() {
  current_ = proc_self_maps_buff_;
}

// Parse a hex value in str and update str.
static uptr ParseHex(char **str) {
  uptr x = 0;
  char *s;
  for (s = *str; ; s++) {
    char c = *s;
    uptr v = 0;
    if (c >= '0' && c <= '9')
      v = c - '0';
    else if (c >= 'a' && c <= 'f')
      v = c - 'a' + 10;
    else if (c >= 'A' && c <= 'F')
      v = c - 'A' + 10;
    else
      break;
    x = x * 16 + v;
  }
  *str = s;
  return x;
}

static bool IsOnOf(char c, char c1, char c2) {
  return c == c1 || c == c2;
}

static bool IsDecimal(char c) {
  return c >= '0' && c <= '9';
}

bool ProcessMaps::Next(uptr *start, uptr *end, uptr *offset,
                       char filename[], uptr filename_size) {
  char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
  if (current_ >= last) return false;
  uptr dummy;
  if (!start) start = &dummy;
  if (!end) end = &dummy;
  if (!offset) offset = &dummy;
  char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
  if (next_line == 0)
    next_line = last;
  // Example: 08048000-08056000 r-xp 00000000 03:0c 64593   /foo/bar
  *start = ParseHex(&current_);
  CHECK(*current_++ == '-');
  *end = ParseHex(&current_);
  CHECK(*current_++ == ' ');
  CHECK(IsOnOf(*current_++, '-', 'r'));
  CHECK(IsOnOf(*current_++, '-', 'w'));
  CHECK(IsOnOf(*current_++, '-', 'x'));
  CHECK(IsOnOf(*current_++, 's', 'p'));
  CHECK(*current_++ == ' ');
  *offset = ParseHex(&current_);
  CHECK(*current_++ == ' ');
  ParseHex(&current_);
  CHECK(*current_++ == ':');
  ParseHex(&current_);
  CHECK(*current_++ == ' ');
  while (IsDecimal(*current_))
    current_++;
  CHECK(*current_++ == ' ');
  // Skip spaces.
  while (current_ < next_line && *current_ == ' ')
    current_++;
  // Fill in the filename.
  uptr i = 0;
  while (current_ < next_line) {
    if (filename && i < filename_size - 1)
      filename[i++] = *current_;
    current_++;
  }
  if (filename && i < filename_size)
    filename[i] = 0;
  current_ = next_line + 1;
  return true;
}

// Gets the object name and the offset by walking ProcessMaps.
bool ProcessMaps::GetObjectNameAndOffset(uptr addr, uptr *offset,
                                         char filename[],
                                         uptr filename_size) {
  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
}

}  // namespace __sanitizer

#endif  // __linux__
<commit_msg>[asan] fix lint<commit_after>//===-- sanitizer_linux.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements linux-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//
#ifdef __linux__

#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_procmaps.h"

#include <fcntl.h>
#include <pthread.h>
#include <sched.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

namespace __sanitizer {

// --------------- sanitizer_libc.h
void *internal_mmap(void *addr, uptr length, int prot, int flags,
                    int fd, u64 offset) {
#if __WORDSIZE == 64
  return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
#else
  return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
#endif
}

int internal_munmap(void *addr, uptr length) {
  return syscall(__NR_munmap, addr, length);
}

int internal_close(fd_t fd) {
  return syscall(__NR_close, fd);
}

fd_t internal_open(const char *filename, bool write) {
  return syscall(__NR_open, filename,
      write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
}

uptr internal_read(fd_t fd, void *buf, uptr count) {
  return (uptr)syscall(__NR_read, fd, buf, count);
}

uptr internal_write(fd_t fd, const void *buf, uptr count) {
  return (uptr)syscall(__NR_write, fd, buf, count);
}

uptr internal_filesize(fd_t fd) {
  struct stat st = {};
  if (syscall(__NR_fstat, fd, &st))
    return -1;
  return (uptr)st.st_size;
}

int internal_dup2(int oldfd, int newfd) {
  return syscall(__NR_dup2, oldfd, newfd);
}

int internal_sched_yield() {
  return syscall(__NR_sched_yield);
}

// ----------------- sanitizer_common.h
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                uptr *stack_bottom) {
  static const uptr kMaxThreadStackSize = 256 * (1 << 20);  // 256M
  CHECK(stack_top);
  CHECK(stack_bottom);
  if (at_initialization) {
    // This is the main thread. Libpthread may not be initialized yet.
    struct rlimit rl;
    CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);

    // Find the mapping that contains a stack variable.
    ProcessMaps proc_maps;
    uptr start, end, offset;
    uptr prev_end = 0;
    while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
      if ((uptr)&rl < end)
        break;
      prev_end = end;
    }
    CHECK((uptr)&rl >= start && (uptr)&rl < end);

    // Get stacksize from rlimit, but clip it so that it does not overlap
    // with other mappings.
    uptr stacksize = rl.rlim_cur;
    if (stacksize > end - prev_end)
      stacksize = end - prev_end;
    // When running with unlimited stack size, we still want to set some limit.
    // The unlimited stack size is caused by 'ulimit -s unlimited'.
    // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
    if (stacksize > kMaxThreadStackSize)
      stacksize = kMaxThreadStackSize;
    *stack_top = end;
    *stack_bottom = end - stacksize;
    return;
  }
  pthread_attr_t attr;
  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
  uptr stacksize = 0;
  void *stackaddr = 0;
  pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
  pthread_attr_destroy(&attr);

  *stack_top = (uptr)stackaddr + stacksize;
  *stack_bottom = (uptr)stackaddr;
  CHECK(stacksize < kMaxThreadStackSize);  // Sanity check.
}

// Like getenv, but reads env directly from /proc and does not use libc.
// This function should be called first inside __asan_init.
const char *GetEnv(const char *name) {
  static char *environ;
  static uptr len;
  static bool inited;
  if (!inited) {
    inited = true;
    uptr environ_size;
    len = ReadFileToBuffer("/proc/self/environ",
                           &environ, &environ_size, 1 << 26);
  }
  if (!environ || len == 0) return 0;
  uptr namelen = internal_strlen(name);
  const char *p = environ;
  while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
    // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
    const char* endp =
        (char*)internal_memchr(p, '\0', len - (p - environ));
    if (endp == 0)  // this entry isn't NUL terminated
      return 0;
    else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
      return p + namelen + 1;  // point after =
    p = endp + 1;
  }
  return 0;  // Not found.
}

// ----------------- sanitizer_procmaps.h
ProcessMaps::ProcessMaps() {
  proc_self_maps_buff_len_ =
      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
                       &proc_self_maps_buff_mmaped_size_, 1 << 26);
  CHECK_GT(proc_self_maps_buff_len_, 0);
  // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
  Reset();
}

ProcessMaps::~ProcessMaps() {
  UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
}

void ProcessMaps::Reset() {
  current_ = proc_self_maps_buff_;
}

// Parse a hex value in str and update str.
static uptr ParseHex(char **str) {
  uptr x = 0;
  char *s;
  for (s = *str; ; s++) {
    char c = *s;
    uptr v = 0;
    if (c >= '0' && c <= '9')
      v = c - '0';
    else if (c >= 'a' && c <= 'f')
      v = c - 'a' + 10;
    else if (c >= 'A' && c <= 'F')
      v = c - 'A' + 10;
    else
      break;
    x = x * 16 + v;
  }
  *str = s;
  return x;
}

static bool IsOnOf(char c, char c1, char c2) {
  return c == c1 || c == c2;
}

static bool IsDecimal(char c) {
  return c >= '0' && c <= '9';
}

bool ProcessMaps::Next(uptr *start, uptr *end, uptr *offset,
                       char filename[], uptr filename_size) {
  char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
  if (current_ >= last) return false;
  uptr dummy;
  if (!start) start = &dummy;
  if (!end) end = &dummy;
  if (!offset) offset = &dummy;
  char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
  if (next_line == 0)
    next_line = last;
  // Example: 08048000-08056000 r-xp 00000000 03:0c 64593   /foo/bar
  *start = ParseHex(&current_);
  CHECK_EQ(*current_++, '-');
  *end = ParseHex(&current_);
  CHECK_EQ(*current_++, ' ');
  CHECK(IsOnOf(*current_++, '-', 'r'));
  CHECK(IsOnOf(*current_++, '-', 'w'));
  CHECK(IsOnOf(*current_++, '-', 'x'));
  CHECK(IsOnOf(*current_++, 's', 'p'));
  CHECK_EQ(*current_++, ' ');
  *offset = ParseHex(&current_);
  CHECK_EQ(*current_++, ' ');
  ParseHex(&current_);
  CHECK_EQ(*current_++, ':');
  ParseHex(&current_);
  CHECK_EQ(*current_++, ' ');
  while (IsDecimal(*current_))
    current_++;
  CHECK_EQ(*current_++, ' ');
  // Skip spaces.
  while (current_ < next_line && *current_ == ' ')
    current_++;
  // Fill in the filename.
  uptr i = 0;
  while (current_ < next_line) {
    if (filename && i < filename_size - 1)
      filename[i++] = *current_;
    current_++;
  }
  if (filename && i < filename_size)
    filename[i] = 0;
  current_ = next_line + 1;
  return true;
}

// Gets the object name and the offset by walking ProcessMaps.
bool ProcessMaps::GetObjectNameAndOffset(uptr addr, uptr *offset,
                                         char filename[],
                                         uptr filename_size) {
  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
}

}  // namespace __sanitizer

#endif  // __linux__
<|endoftext|>


<commit_before>class destroyCity {
        title = "Ambient - Destroy City";
        values[]= {0};
        texts[]= {" "};
        default = 0;
};
class destroyCityIntensity {
        title = "    Enable Destroyed Cities";
        values[]= {0,1,2,3};
        texts[]= {"Off", "Low", "Med", "High"};
        default = 0;
};
class destroyCityFire {
        title = "    Enable Destroyed City Building Fires";
        values[]= {0,1};
        texts[]= {"Off", "On"};
        default = 0;
};
<commit_msg>- Fixed params to new format for Destroy City<commit_after>class destroyCityIntensity {
        title = "    Enable Destroyed Cities";
        values[]= {0,1,2,3};
        texts[]= {"Off", "Low", "Med", "High"};
        default = 0;
};
class destroyCityFire {
        title = "    Enable Destroyed City Building Fires";
        values[]= {0,1};
        texts[]= {"Off", "On"};
        default = 0;
};
<|endoftext|>


<commit_before>/**\file
 * \brief Test cases for the set templates
 *
 * \copyright
 * Copyright (c) 2012-2014, ef.gy Project Members
 * \copyright
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * \copyright
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * \copyright
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * \see Project Documentation: http://ef.gy/documentation/libefgy
 * \see Project Source Code: http://git.becquerel.org/jyujin/libefgy.git
 */

#include <iostream>

#include <ef.gy/test-case.h>
#include <ef.gy/set.h>

using namespace efgy;
using namespace efgy::math;
using efgy::test::next_integer;

int testSet(std::ostream &log)
{
    set<unsigned int> empty();

    set<unsigned int> empty2();

    if(empty != empty2)
    {
	log << "two empty sets cannot be inequal to each other ";
	return next_integer();
    }

    const int a[4] = {0, 1, 2, 3};

    set<int> s_a(&a[0], 4);

    int b[3] = {0, 1, 2};
    set<int> s_b(&b[0], 3);

    if(s_a == s_b)
    {
	log << "sets of two different sizes cannot be equal to each other";
    	return next_integer();
    }

    const int a_permuted[4] = {3, 2, 1, 0};
    set<int> s_a_permuted(&a_permuted[0], 3);

    if(!(s_a == s_a_permuted))
    {
        log << "sets with the same elements in different order should be equal";
        return next_integer();
    }
    return 0;
}

TEST_BATCH(testSet)
<commit_msg>i still wonder about how the compiler gets confused about functions vs default constructors<commit_after>/**\file
 * \brief Test cases for the set templates
 *
 * \copyright
 * Copyright (c) 2012-2014, ef.gy Project Members
 * \copyright
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * \copyright
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * \copyright
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * \see Project Documentation: http://ef.gy/documentation/libefgy
 * \see Project Source Code: http://git.becquerel.org/jyujin/libefgy.git
 */

#include <iostream>

#include <ef.gy/test-case.h>
#include <ef.gy/set.h>

using namespace efgy;
using namespace efgy::math;
using efgy::test::next_integer;

int testSet(std::ostream &log)
{
    set<unsigned int> empty;
    set<unsigned int> empty2;

    if(empty != empty2)
    {
	log << "two empty sets cannot be inequal to each other ";
	return next_integer();
    }

    const int a[4] = {0, 1, 2, 3};

    set<int> s_a(&a[0], 4);

    int b[3] = {0, 1, 2};
    set<int> s_b(&b[0], 3);

    if(s_a == s_b)
    {
	log << "sets of two different sizes cannot be equal to each other";
    	return next_integer();
    }

    const int a_permuted[4] = {3, 2, 1, 0};
    set<int> s_a_permuted(&a_permuted[0], 3);

    if(!(s_a == s_a_permuted))
    {
        log << "sets with the same elements in different order should be equal";
        return next_integer();
    }
    return 0;
}

TEST_BATCH(testSet)
<|endoftext|>


<commit_before>/***************************************
** Tsunagari Tile Engine              **
** reader.cpp                         **
** Copyright 2011-2013 PariahSoft LLC **
***************************************/

// **********
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// **********

#include <errno.h>
#include <stdlib.h>

#include <Gosu/Bitmap.hpp>
#include <Gosu/Image.hpp>
#include <Gosu/IO.hpp>
#include <map>
#include <physfs.h>

#include "cache.h"
#include "cache-template.cpp"
#include "client-conf.h"
#include "formatter.h"
#include "log.h"
#include "reader.h"
#include "window.h"
#include "xml.h"

#define ASSERT(x)  if (!(x)) { return false; }

typedef std::shared_ptr<xmlDtd> DTDRef;
typedef std::shared_ptr<std::string> StringRef;

// Caches that store processed, game-ready objects. Garbage collected.
static Cache<ImageRef> images;
static Cache<TiledImageRef> tiles;
static Cache<SampleRef> sounds;
static Cache<XMLRef> xmls;
static Cache<StringRef> texts;

// DTDs don't expire. No garbage collection.
typedef std::map<std::string, DTDRef> DTDMap;
static DTDMap dtds;

static std::string path(const std::string& entryName)
{
	// XXX: archive might not be world
	return conf.worldFilename + "/" + entryName;
}

template <class T>
static bool readFromDisk(const std::string& name, T& buf)
{
	PHYSFS_sint64 size;
	PHYSFS_File* zf;

	if (!PHYSFS_exists(name.c_str())) {
		Log::err("Reader", Formatter("%: file missing")
				% path(name));
		return false;
	}

	zf = PHYSFS_openRead(name.c_str());
	if (!zf) {
		Log::err("Reader", Formatter("%: error opening file: %")
				% path(name) % PHYSFS_getLastError());
		return false;
	}

	size = PHYSFS_fileLength(zf);
	if (size == -1) {
		Log::err("Reader", Formatter("%: could not determine file size: %")
				% path(name) % PHYSFS_getLastError());
		PHYSFS_close(zf);
		return false;
	}
	else if (size > std::numeric_limits<uint32_t>::max()) {
		// FIXME: Technically, we just need to issue multiple calls to
		// PHYSFS_read. Fix when needed.
		Log::err("Reader", Formatter("%: file too long (>4GB)")
				% path(name));
		PHYSFS_close(zf);
		return false;
	}
	else if (size < -1) {
		Log::err("Reader", Formatter("%: invalid file size: %")
				% path(name) % PHYSFS_getLastError());
		PHYSFS_close(zf);
		return false;
	}

	buf.resize((size_t)size);
	if (size == 0) {
		PHYSFS_close(zf);
		return true;
	}

	if (PHYSFS_read(zf, (char*)(buf.data()),
			(PHYSFS_uint32)size, 1) != 1) {
		Log::err("Reader", Formatter("%: error reading file: %")
				% path(name) % PHYSFS_getLastError());
		PHYSFS_close(zf);
		return false;
	}

	PHYSFS_close(zf);
	return true;
}

// FIXME: Should be moved to xml.cpp!!!!!!
static DTDRef parseDTD(const std::string& path)
{
	xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;

	std::string bytes = Reader::readString(path);
	if (bytes.empty())
		return DTDRef();

	xmlParserInputBuffer* input = xmlParserInputBufferCreateMem(
			bytes.c_str(), (int)bytes.size(), enc);
	if (!input)
		return DTDRef();

	xmlDtd* dtd = xmlIOParseDTD(NULL, input, enc);
	if (!dtd)
		return DTDRef();

	return DTDRef(dtd, xmlFreeDtd);
}

// FIXME: Should be moved to xml.cpp!!!!!!
static bool preloadDTDs()
{
	ASSERT(dtds["dtd/area.dtd"]   = parseDTD("dtd/area.dtd"));
	ASSERT(dtds["dtd/entity.dtd"] = parseDTD("dtd/entity.dtd"));
	ASSERT(dtds["dtd/tsx.dtd"] = parseDTD("dtd/tsx.dtd"));
	ASSERT(dtds["dtd/world.dtd"]  = parseDTD("dtd/world.dtd"));
	return true;
}

static xmlDtd* getDTD(const std::string& name)
{
	DTDMap::iterator it = dtds.find(name);
	return it == dtds.end() ? NULL : it->second.get();
}

static XMLDoc* readXMLDoc(const std::string& name,
                          const std::string& dtdPath)
{
	std::string p = path(name);
	std::string data = Reader::readString(name);
	xmlDtd* dtd = getDTD(dtdPath);

	if (!dtd || data.empty())
		return NULL;
	XMLDoc* doc = new XMLDoc;
	if (!doc->init(p, data, dtd)) {
		delete doc;
		return NULL;
	}
	return doc;
}

static bool callInitpy(const std::string& archivePath)
{
	// ASSERT(Reader::prependPath(archivePath));
	// bool exists = Reader::resourceExists("__init__.py");
	// Log::info(archivePath,
	// 	std::string("__init__.py: ") +
	// 	(exists ? "found" : "not found"));
	// if (exists)
	// 	ASSERT(Script::create("__init__"));
	// ASSERT(Reader::rmPath(archivePath));
	return true;
}

bool Reader::init()
{
	ASSERT(prependPath(BASE_ZIP_PATH));

	// DTDs must be loaded from BASE_ZIP. They cannot be allowed to be
	// loaded from the world.
	ASSERT(preloadDTDs());

	ASSERT(prependPath(conf.worldFilename));
	for (Conf::StringVector::const_iterator it = conf.dataPath.begin(); it != conf.dataPath.end(); it++) {
		const std::string archive = *it;
		ASSERT(prependPath(archive));
	}

	return true;
}

bool Reader::prependPath(const std::string& path)
{
	int err = PHYSFS_mount(path.c_str(), NULL, 0);
	if (err == 0) {
		Log::fatal("Reader", Formatter("%: could not open archive: %")
				% path % PHYSFS_getLastError());
		return false;
	}

	return true;
}

bool Reader::appendPath(const std::string& path)
{
	int err = PHYSFS_mount(path.c_str(), NULL, 1);
	if (err == 0) {
		Log::fatal("Reader", Formatter("%: could not open archive: %")
				% path % PHYSFS_getLastError());
		return false;
	}

	return true;
}

bool Reader::rmPath(const std::string& path)
{
	int err = PHYSFS_removeFromSearchPath(path.c_str());
	if (err == 0) {
		Log::err("Reader", Formatter("libphysfs: %: %")
				% path % PHYSFS_getLastError());
		return false;
	}

	return true;
}

bool Reader::resourceExists(const std::string& name)
{
	return PHYSFS_exists(name.c_str());
}

bool Reader::directoryExists(const std::string& name)
{
	return resourceExists(name) && PHYSFS_isDirectory(name.c_str());
}

bool Reader::fileExists(const std::string& name)
{
	return resourceExists(name) && !PHYSFS_isDirectory(name.c_str());
}

Gosu::Buffer* Reader::readBuffer(const std::string& name)
{
	Gosu::Buffer* buf = new Gosu::Buffer();

	if (readFromDisk(name, *buf)) {
		return buf;
	}
	else {
		delete buf;
		return NULL;
	}
}

std::string Reader::readString(const std::string& name)
{
	std::string str;
	return readFromDisk(name, str) ? str : "";
}

ImageRef Reader::getImage(const std::string& name)
{
	ImageRef existing = images.lifetimeRequest(name);
	if (existing)
		return existing;

	std::unique_ptr<Gosu::Buffer> buffer(readBuffer(name));
	if (!buffer)
		return ImageRef();

	ImageRef result(Image::create(buffer->data(), buffer->size()));
	if (!result)
		return ImageRef();

	images.lifetimePut(name, result);
	return result;
}

TiledImageRef Reader::getTiledImage(const std::string& name,
		int w, int h)
{
	TiledImageRef existing = tiles.momentaryRequest(name);
	if (existing)
		return existing;

	if (w <= 0 || h <= 0)
		return TiledImageRef();

	std::unique_ptr<Gosu::Buffer> buffer(readBuffer(name));
	if (!buffer)
		return TiledImageRef();

	TiledImageRef result(
		TiledImage::create(buffer->data(), buffer->size(),
			(unsigned int)w, (unsigned int)h)
	);
	if (!result)
		return TiledImageRef();

	tiles.momentaryPut(name, result);
	return result;
}

SampleRef Reader::getSample(const std::string& name)
{
	if (!conf.audioEnabled)
		return SampleRef();

	SampleRef existing = sounds.lifetimeRequest(name);
	if (existing)
		return existing;

	std::unique_ptr<Gosu::Buffer> buffer(readBuffer(name));
	if (!buffer)
		return SampleRef();
	SampleRef result(new Sound(new Gosu::Sample(buffer->frontReader())));

	sounds.lifetimePut(name, result);
	return result;
}

XMLRef Reader::getXMLDoc(const std::string& name,
                            const std::string& dtdFile)
{
	XMLRef existing = xmls.momentaryRequest(name);
	if (existing)
		return existing;

	XMLRef result(readXMLDoc(name, dtdFile));

	xmls.momentaryPut(name, result);
	return result;
}

std::string Reader::getText(const std::string& name)
{
	StringRef existing = texts.momentaryRequest(name);
	if (existing)
		return *existing.get();

	StringRef result(new std::string(readString(name)));

	texts.momentaryPut(name, result);
	return *result.get();
}

void Reader::garbageCollect()
{
	images.garbageCollect();
	tiles.garbageCollect();
	sounds.garbageCollect();
	// songs.garbageCollect();
	xmls.garbageCollect();
	texts.garbageCollect();
}

void exportReader()
{
}

<commit_msg>reader: remove `bool callInitPy`<commit_after>/***************************************
** Tsunagari Tile Engine              **
** reader.cpp                         **
** Copyright 2011-2013 PariahSoft LLC **
***************************************/

// **********
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// **********

#include <errno.h>
#include <stdlib.h>

#include <Gosu/Bitmap.hpp>
#include <Gosu/Image.hpp>
#include <Gosu/IO.hpp>
#include <map>
#include <physfs.h>

#include "cache.h"
#include "cache-template.cpp"
#include "client-conf.h"
#include "formatter.h"
#include "log.h"
#include "reader.h"
#include "window.h"
#include "xml.h"

#define ASSERT(x)  if (!(x)) { return false; }

typedef std::shared_ptr<xmlDtd> DTDRef;
typedef std::shared_ptr<std::string> StringRef;

// Caches that store processed, game-ready objects. Garbage collected.
static Cache<ImageRef> images;
static Cache<TiledImageRef> tiles;
static Cache<SampleRef> sounds;
static Cache<XMLRef> xmls;
static Cache<StringRef> texts;

// DTDs don't expire. No garbage collection.
typedef std::map<std::string, DTDRef> DTDMap;
static DTDMap dtds;

static std::string path(const std::string& entryName)
{
	// XXX: archive might not be world
	return conf.worldFilename + "/" + entryName;
}

template <class T>
static bool readFromDisk(const std::string& name, T& buf)
{
	PHYSFS_sint64 size;
	PHYSFS_File* zf;

	if (!PHYSFS_exists(name.c_str())) {
		Log::err("Reader", Formatter("%: file missing")
				% path(name));
		return false;
	}

	zf = PHYSFS_openRead(name.c_str());
	if (!zf) {
		Log::err("Reader", Formatter("%: error opening file: %")
				% path(name) % PHYSFS_getLastError());
		return false;
	}

	size = PHYSFS_fileLength(zf);
	if (size == -1) {
		Log::err("Reader", Formatter("%: could not determine file size: %")
				% path(name) % PHYSFS_getLastError());
		PHYSFS_close(zf);
		return false;
	}
	else if (size > std::numeric_limits<uint32_t>::max()) {
		// FIXME: Technically, we just need to issue multiple calls to
		// PHYSFS_read. Fix when needed.
		Log::err("Reader", Formatter("%: file too long (>4GB)")
				% path(name));
		PHYSFS_close(zf);
		return false;
	}
	else if (size < -1) {
		Log::err("Reader", Formatter("%: invalid file size: %")
				% path(name) % PHYSFS_getLastError());
		PHYSFS_close(zf);
		return false;
	}

	buf.resize((size_t)size);
	if (size == 0) {
		PHYSFS_close(zf);
		return true;
	}

	if (PHYSFS_read(zf, (char*)(buf.data()),
			(PHYSFS_uint32)size, 1) != 1) {
		Log::err("Reader", Formatter("%: error reading file: %")
				% path(name) % PHYSFS_getLastError());
		PHYSFS_close(zf);
		return false;
	}

	PHYSFS_close(zf);
	return true;
}

// FIXME: Should be moved to xml.cpp!!!!!!
static DTDRef parseDTD(const std::string& path)
{
	xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;

	std::string bytes = Reader::readString(path);
	if (bytes.empty())
		return DTDRef();

	xmlParserInputBuffer* input = xmlParserInputBufferCreateMem(
			bytes.c_str(), (int)bytes.size(), enc);
	if (!input)
		return DTDRef();

	xmlDtd* dtd = xmlIOParseDTD(NULL, input, enc);
	if (!dtd)
		return DTDRef();

	return DTDRef(dtd, xmlFreeDtd);
}

// FIXME: Should be moved to xml.cpp!!!!!!
static bool preloadDTDs()
{
	ASSERT(dtds["dtd/area.dtd"]   = parseDTD("dtd/area.dtd"));
	ASSERT(dtds["dtd/entity.dtd"] = parseDTD("dtd/entity.dtd"));
	ASSERT(dtds["dtd/tsx.dtd"] = parseDTD("dtd/tsx.dtd"));
	ASSERT(dtds["dtd/world.dtd"]  = parseDTD("dtd/world.dtd"));
	return true;
}

static xmlDtd* getDTD(const std::string& name)
{
	DTDMap::iterator it = dtds.find(name);
	return it == dtds.end() ? NULL : it->second.get();
}

static XMLDoc* readXMLDoc(const std::string& name,
                          const std::string& dtdPath)
{
	std::string p = path(name);
	std::string data = Reader::readString(name);
	xmlDtd* dtd = getDTD(dtdPath);

	if (!dtd || data.empty())
		return NULL;
	XMLDoc* doc = new XMLDoc;
	if (!doc->init(p, data, dtd)) {
		delete doc;
		return NULL;
	}
	return doc;
}

bool Reader::init()
{
	ASSERT(prependPath(BASE_ZIP_PATH));

	// DTDs must be loaded from BASE_ZIP. They cannot be allowed to be
	// loaded from the world.
	ASSERT(preloadDTDs());

	ASSERT(prependPath(conf.worldFilename));
	for (Conf::StringVector::const_iterator it = conf.dataPath.begin(); it != conf.dataPath.end(); it++) {
		const std::string archive = *it;
		ASSERT(prependPath(archive));
	}

	return true;
}

bool Reader::prependPath(const std::string& path)
{
	int err = PHYSFS_mount(path.c_str(), NULL, 0);
	if (err == 0) {
		Log::fatal("Reader", Formatter("%: could not open archive: %")
				% path % PHYSFS_getLastError());
		return false;
	}

	return true;
}

bool Reader::appendPath(const std::string& path)
{
	int err = PHYSFS_mount(path.c_str(), NULL, 1);
	if (err == 0) {
		Log::fatal("Reader", Formatter("%: could not open archive: %")
				% path % PHYSFS_getLastError());
		return false;
	}

	return true;
}

bool Reader::rmPath(const std::string& path)
{
	int err = PHYSFS_removeFromSearchPath(path.c_str());
	if (err == 0) {
		Log::err("Reader", Formatter("libphysfs: %: %")
				% path % PHYSFS_getLastError());
		return false;
	}

	return true;
}

bool Reader::resourceExists(const std::string& name)
{
	return PHYSFS_exists(name.c_str());
}

bool Reader::directoryExists(const std::string& name)
{
	return resourceExists(name) && PHYSFS_isDirectory(name.c_str());
}

bool Reader::fileExists(const std::string& name)
{
	return resourceExists(name) && !PHYSFS_isDirectory(name.c_str());
}

Gosu::Buffer* Reader::readBuffer(const std::string& name)
{
	Gosu::Buffer* buf = new Gosu::Buffer();

	if (readFromDisk(name, *buf)) {
		return buf;
	}
	else {
		delete buf;
		return NULL;
	}
}

std::string Reader::readString(const std::string& name)
{
	std::string str;
	return readFromDisk(name, str) ? str : "";
}

ImageRef Reader::getImage(const std::string& name)
{
	ImageRef existing = images.lifetimeRequest(name);
	if (existing)
		return existing;

	std::unique_ptr<Gosu::Buffer> buffer(readBuffer(name));
	if (!buffer)
		return ImageRef();

	ImageRef result(Image::create(buffer->data(), buffer->size()));
	if (!result)
		return ImageRef();

	images.lifetimePut(name, result);
	return result;
}

TiledImageRef Reader::getTiledImage(const std::string& name,
		int w, int h)
{
	TiledImageRef existing = tiles.momentaryRequest(name);
	if (existing)
		return existing;

	if (w <= 0 || h <= 0)
		return TiledImageRef();

	std::unique_ptr<Gosu::Buffer> buffer(readBuffer(name));
	if (!buffer)
		return TiledImageRef();

	TiledImageRef result(
		TiledImage::create(buffer->data(), buffer->size(),
			(unsigned int)w, (unsigned int)h)
	);
	if (!result)
		return TiledImageRef();

	tiles.momentaryPut(name, result);
	return result;
}

SampleRef Reader::getSample(const std::string& name)
{
	if (!conf.audioEnabled)
		return SampleRef();

	SampleRef existing = sounds.lifetimeRequest(name);
	if (existing)
		return existing;

	std::unique_ptr<Gosu::Buffer> buffer(readBuffer(name));
	if (!buffer)
		return SampleRef();
	SampleRef result(new Sound(new Gosu::Sample(buffer->frontReader())));

	sounds.lifetimePut(name, result);
	return result;
}

XMLRef Reader::getXMLDoc(const std::string& name,
                            const std::string& dtdFile)
{
	XMLRef existing = xmls.momentaryRequest(name);
	if (existing)
		return existing;

	XMLRef result(readXMLDoc(name, dtdFile));

	xmls.momentaryPut(name, result);
	return result;
}

std::string Reader::getText(const std::string& name)
{
	StringRef existing = texts.momentaryRequest(name);
	if (existing)
		return *existing.get();

	StringRef result(new std::string(readString(name)));

	texts.momentaryPut(name, result);
	return *result.get();
}

void Reader::garbageCollect()
{
	images.garbageCollect();
	tiles.garbageCollect();
	sounds.garbageCollect();
	// songs.garbageCollect();
	xmls.garbageCollect();
	texts.garbageCollect();
}

void exportReader()
{
}

<|endoftext|>