<commit_before>#include "stdafx.h"
#include <dukat/surface.h>
#include <dukat/bit.h>
#include <dukat/log.h>
#include <dukat/sdlutil.h>

namespace dukat
{
	// Struct for manipulating 24-bit surfaces
	struct Uint24 { Uint8 c[3]; };

	Surface::Surface(int width, int height, uint32_t format)
	{
		int bpp;
		uint32_t rmask, gmask, bmask, amask;
		SDL_PixelFormatEnumToMasks(format, &bpp, &rmask, &gmask, &bmask, &amask);
		surface = SDL_CreateRGBSurface(0, width, height, bpp, rmask, gmask, bmask, amask);
		if (surface == nullptr)
			throw std::runtime_error("Could not create RGB surface.");
	}

	Surface::Surface(SDL_Surface* surface) : surface(surface)
	{
		if (surface == nullptr)
			throw std::runtime_error("Failed to create surface for invalid SDL_Surface.");
	}

	Surface::~Surface(void)
	{
		if (surface != nullptr)
		{
			SDL_FreeSurface(surface);
			surface = nullptr;
		}
	}

	SDL_Color Surface::map_color(SDL_PixelFormat* fmt, uint32_t pixel) const
	{
		uint32_t temp;
		SDL_Color result;

		// Get Red component
		temp = pixel & fmt->Rmask;	// Isolate red component
		temp = temp >> fmt->Rshift;	// Shift it down to 8-bit
		temp = temp << fmt->Rloss;	// Expand to a full 8-bit number
		result.r = static_cast<uint8_t>(temp);

		// Get Green component
		temp = pixel & fmt->Gmask;	// Isolate green component
		temp = temp >> fmt->Gshift;	// Shift it down to 8-bit
		temp = temp << fmt->Gloss;	// Expand to a full 8-bit number
		result.g = static_cast<uint8_t>(temp);

		// Get Blue component
		temp = pixel & fmt->Bmask;	// Isolate blue component
		temp = temp >> fmt->Bshift;	// Shift it down to 8-bit
		temp = temp << fmt->Bloss;	// Expand to a full 8-bit number
		result.b = static_cast<uint8_t>(temp);

		// Get Alpha component
		temp = pixel & fmt->Amask;	// Isolate alpha component
		temp = temp >> fmt->Ashift;	// Shift it down to 8-bit
		temp = temp << fmt->Aloss;	// Expand to a full 8-bit number
		result.a = static_cast<uint8_t>(temp);
		return result;
	}

	void Surface::query_pixel_format(GLenum& format, GLenum& type) const
	{
		switch (surface->format->format)
		{
#ifdef OPENGL_CORE
		// 24 bit
		case SDL_PIXELFORMAT_BGR24:
		case SDL_PIXELFORMAT_BGR888:
			format = GL_BGR;
			type = GL_UNSIGNED_BYTE;
		case SDL_PIXELFORMAT_RGB24:
		case SDL_PIXELFORMAT_RGB888:
			format = GL_RGB;
			type = GL_UNSIGNED_BYTE;
			break;
		// 32 bit
		case SDL_PIXELFORMAT_ABGR8888:
			format = GL_RGBA;
			type = surface->format->Rshift == 0xff ? GL_UNSIGNED_INT_8_8_8_8 : GL_UNSIGNED_INT_8_8_8_8_REV;
			break;
		case SDL_PIXELFORMAT_RGBA8888:
			format = GL_RGBA;
			type = surface->format->Rshift == 0xff ? GL_UNSIGNED_INT_8_8_8_8_REV : GL_UNSIGNED_INT_8_8_8_8;
			break;
		case SDL_PIXELFORMAT_BGRA8888:
			format = GL_BGRA;
			type = surface->format->Bshift == 0xff ? GL_UNSIGNED_INT_8_8_8_8_REV : GL_UNSIGNED_INT_8_8_8_8;
			break;
#else
		// 32 bit
		case SDL_PIXELFORMAT_ABGR8888:
			format = GL_RGBA;
			type = surface->format->Rshift == 0xff ? GL_UNSIGNED_BYTE : GL_UNSIGNED_BYTE;
			break;
		case SDL_PIXELFORMAT_RGBA8888:
			format = GL_RGBA;
			type = surface->format->Rshift == 0xff ? GL_UNSIGNED_BYTE : GL_UNSIGNED_BYTE;
			break;
#endif
		default:
			log->warn("Unsupported pixel format: {}", SDL_GetPixelFormatName(surface->format->format));
			format = 0;
			type = 0;
			break;
		}
	}

	const uint32_t& Surface::operator()(int x, int y) const
	{
		assert(x >= 0 && x < surface->w&& y >= 0 && y < surface->h);
		return static_cast<uint32_t*>(surface->pixels)[y * surface->w + x];
	}

	uint32_t& Surface::operator()(int x, int y)
	{
		assert(x >= 0 && x < surface->w && y >= 0 && y < surface->h);
		return static_cast<uint32_t*>(surface->pixels)[y * surface->w + x];
	}

	uint32_t Surface::get_pixel(int x, int y) const
	{
		// Here p is the address to the pixel we want to retrieve
		auto p = static_cast<uint8_t*>(surface->pixels) + y * surface->pitch + x * surface->format->BytesPerPixel;
		switch (surface->format->BytesPerPixel)
		{
		case 1:
			return *p;
		case 2:
			return *reinterpret_cast<uint16_t*>(p);
		case 3:
			if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
				return p[0] << 16 | p[1] << 8 | p[2];
			else
				return p[0] | p[1] << 8 | p[2] << 16;
		case 4:
			return *reinterpret_cast<uint32_t*>(p);
		default:
			return 0;       // shouldn't happen, but avoids warnings
		}
	}

	void Surface::fill(uint32_t color)
	{
		SDL_FillRect(surface, nullptr, color);
	}

	void Surface::replace(uint32_t src_color, uint32_t dest_color)
	{
		auto ptr = static_cast<uint32_t*>(surface->pixels);
		auto end = ptr + surface->w * surface->h;
		while (ptr < end)
		{
			if (*ptr == src_color)
				*ptr = dest_color;
			++ptr;
		}
	}

	void Surface::convert_format(uint32_t format)
	{
		auto tmp = SDL_ConvertSurfaceFormat(surface, format, 0);
		if (tmp == nullptr)
		{
			std::stringstream ss;
			ss << "Could not convert surface: " << SDL_GetError();
			throw std::runtime_error(ss.str());
		}
		SDL_FreeSurface(surface);
		surface = tmp;
	}

	void Surface::blend(const Surface& another)
	{
		SDL_BlitSurface(another.surface, nullptr, surface, nullptr);
	}

	void Surface::blend(const Surface& another, const Rect& src, const Rect& dest)
	{
		SDL_BlitSurface(another.surface, (SDL_Rect*)&src, surface, (SDL_Rect*)&dest);
	}

	void Surface::blend(const Surface& another, int x, int y)
	{
		SDL_Rect r{ x, y, another.width(), another.height() };
		SDL_BlitSurface(another.surface, nullptr, surface, &r);
	}

	void Surface::blend_flip_h(const Surface& another, const Rect& src, const Rect& dest)
	{
		Surface tmp_surface(SDL_CreateRGBSurface(0, src.w, src.h, surface->format->BitsPerPixel,
			surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask));
		tmp_surface.blend(*this, src, src);
		tmp_surface.flip_horizontal();
		SDL_BlitSurface(tmp_surface.surface, nullptr, another.surface, (SDL_Rect*)&dest);
	}

	void Surface::blend_flip_v(const Surface& another, const Rect& src, const Rect& dest)
	{
		Surface tmp_surface(SDL_CreateRGBSurface(0, src.w, src.h, surface->format->BitsPerPixel,
			surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask));
		tmp_surface.blend(*this, src, src);
		tmp_surface.flip_vertical();
		SDL_BlitSurface(tmp_surface.surface, nullptr, another.surface, (SDL_Rect*)&dest);
	}

	void Surface::flip_vertical(void) const
	{
		const auto size = surface->w * surface->h;
		switch (surface->format->BytesPerPixel)
		{
		case 1:
			dukat::flip_vertical(static_cast<uint8_t*>(surface->pixels), static_cast<uint8_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 2:
			dukat::flip_vertical(static_cast<uint16_t*>(surface->pixels), static_cast<uint16_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 3:
			dukat::flip_vertical(static_cast<Uint24*>(surface->pixels), static_cast<Uint24*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 4:
			dukat::flip_vertical(static_cast<uint32_t*>(surface->pixels), static_cast<uint32_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		}
	}

	void Surface::flip_horizontal(void) const
	{
		const auto size = surface->w * surface->h;
		switch (surface->format->BytesPerPixel)
		{
		case 1:
			dukat::flip_horizontal(static_cast<uint8_t*>(surface->pixels), static_cast<uint8_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 2:
			dukat::flip_horizontal(static_cast<uint16_t*>(surface->pixels), static_cast<uint16_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 3:
			dukat::flip_horizontal(static_cast<Uint24*>(surface->pixels), static_cast<Uint24*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 4:
			dukat::flip_horizontal(static_cast<uint32_t*>(surface->pixels), static_cast<uint32_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		}
	}

	void Surface::apply(const std::function<void(int x, int y, SDL_Surface* s, uint32_t& p)>& f)
	{
		auto ptr = static_cast<uint32_t*>(surface->pixels);
		for (auto y = 0; y < surface->h; y++)
		{
			for (auto x = 0; x < surface->w; x++)
			{
				f(x, y, surface, *(ptr++));
			}
		}
	}

#pragma region Utility Functions

	std::unique_ptr<Surface> load_surface(const std::string& filename)
	{
		auto surface = IMG_Load(filename.c_str());
		if (surface == nullptr)
		{
			std::stringstream ss;
			ss << "Could not load surface: " << filename;
			throw std::runtime_error(ss.str());
		}
		return std::make_unique<Surface>(surface);
	}

	void save_surface(const Surface& surface, const std::string& filename)
	{
		auto res = IMG_SavePNG(surface.get_surface(), filename.c_str());
		sdl_check_result(res, "Save surface");
	}

	void replace_surface_colors(Surface& surface, const std::vector<SDL_Color>& src_colors, const std::vector<SDL_Color>& dest_colors)
	{
		assert(src_colors.size() == dest_colors.size());
		for (auto i = 0u; i < src_colors.size(); i++)
		{
			const auto src_color = surface.color(src_colors[i]);
			const auto dest_color = surface.color(dest_colors[i]);
			surface.replace(src_color, dest_color);
		}
	}

#pragma endregion
}<commit_msg>Avoid duplicate replacements<commit_after>#include "stdafx.h"
#include <dukat/surface.h>
#include <dukat/bit.h>
#include <dukat/log.h>
#include <dukat/sdlutil.h>

namespace dukat
{
	// Struct for manipulating 24-bit surfaces
	struct Uint24 { Uint8 c[3]; };

	Surface::Surface(int width, int height, uint32_t format)
	{
		int bpp;
		uint32_t rmask, gmask, bmask, amask;
		SDL_PixelFormatEnumToMasks(format, &bpp, &rmask, &gmask, &bmask, &amask);
		surface = SDL_CreateRGBSurface(0, width, height, bpp, rmask, gmask, bmask, amask);
		if (surface == nullptr)
			throw std::runtime_error("Could not create RGB surface.");
	}

	Surface::Surface(SDL_Surface* surface) : surface(surface)
	{
		if (surface == nullptr)
			throw std::runtime_error("Failed to create surface for invalid SDL_Surface.");
	}

	Surface::~Surface(void)
	{
		if (surface != nullptr)
		{
			SDL_FreeSurface(surface);
			surface = nullptr;
		}
	}

	SDL_Color Surface::map_color(SDL_PixelFormat* fmt, uint32_t pixel) const
	{
		uint32_t temp;
		SDL_Color result;

		// Get Red component
		temp = pixel & fmt->Rmask;	// Isolate red component
		temp = temp >> fmt->Rshift;	// Shift it down to 8-bit
		temp = temp << fmt->Rloss;	// Expand to a full 8-bit number
		result.r = static_cast<uint8_t>(temp);

		// Get Green component
		temp = pixel & fmt->Gmask;	// Isolate green component
		temp = temp >> fmt->Gshift;	// Shift it down to 8-bit
		temp = temp << fmt->Gloss;	// Expand to a full 8-bit number
		result.g = static_cast<uint8_t>(temp);

		// Get Blue component
		temp = pixel & fmt->Bmask;	// Isolate blue component
		temp = temp >> fmt->Bshift;	// Shift it down to 8-bit
		temp = temp << fmt->Bloss;	// Expand to a full 8-bit number
		result.b = static_cast<uint8_t>(temp);

		// Get Alpha component
		temp = pixel & fmt->Amask;	// Isolate alpha component
		temp = temp >> fmt->Ashift;	// Shift it down to 8-bit
		temp = temp << fmt->Aloss;	// Expand to a full 8-bit number
		result.a = static_cast<uint8_t>(temp);
		return result;
	}

	void Surface::query_pixel_format(GLenum& format, GLenum& type) const
	{
		switch (surface->format->format)
		{
#ifdef OPENGL_CORE
		// 24 bit
		case SDL_PIXELFORMAT_BGR24:
		case SDL_PIXELFORMAT_BGR888:
			format = GL_BGR;
			type = GL_UNSIGNED_BYTE;
		case SDL_PIXELFORMAT_RGB24:
		case SDL_PIXELFORMAT_RGB888:
			format = GL_RGB;
			type = GL_UNSIGNED_BYTE;
			break;
		// 32 bit
		case SDL_PIXELFORMAT_ABGR8888:
			format = GL_RGBA;
			type = surface->format->Rshift == 0xff ? GL_UNSIGNED_INT_8_8_8_8 : GL_UNSIGNED_INT_8_8_8_8_REV;
			break;
		case SDL_PIXELFORMAT_RGBA8888:
			format = GL_RGBA;
			type = surface->format->Rshift == 0xff ? GL_UNSIGNED_INT_8_8_8_8_REV : GL_UNSIGNED_INT_8_8_8_8;
			break;
		case SDL_PIXELFORMAT_BGRA8888:
			format = GL_BGRA;
			type = surface->format->Bshift == 0xff ? GL_UNSIGNED_INT_8_8_8_8_REV : GL_UNSIGNED_INT_8_8_8_8;
			break;
#else
		// 32 bit
		case SDL_PIXELFORMAT_ABGR8888:
			format = GL_RGBA;
			type = surface->format->Rshift == 0xff ? GL_UNSIGNED_BYTE : GL_UNSIGNED_BYTE;
			break;
		case SDL_PIXELFORMAT_RGBA8888:
			format = GL_RGBA;
			type = surface->format->Rshift == 0xff ? GL_UNSIGNED_BYTE : GL_UNSIGNED_BYTE;
			break;
#endif
		default:
			log->warn("Unsupported pixel format: {}", SDL_GetPixelFormatName(surface->format->format));
			format = 0;
			type = 0;
			break;
		}
	}

	const uint32_t& Surface::operator()(int x, int y) const
	{
		assert(x >= 0 && x < surface->w&& y >= 0 && y < surface->h);
		return static_cast<uint32_t*>(surface->pixels)[y * surface->w + x];
	}

	uint32_t& Surface::operator()(int x, int y)
	{
		assert(x >= 0 && x < surface->w && y >= 0 && y < surface->h);
		return static_cast<uint32_t*>(surface->pixels)[y * surface->w + x];
	}

	uint32_t Surface::get_pixel(int x, int y) const
	{
		// Here p is the address to the pixel we want to retrieve
		auto p = static_cast<uint8_t*>(surface->pixels) + y * surface->pitch + x * surface->format->BytesPerPixel;
		switch (surface->format->BytesPerPixel)
		{
		case 1:
			return *p;
		case 2:
			return *reinterpret_cast<uint16_t*>(p);
		case 3:
			if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
				return p[0] << 16 | p[1] << 8 | p[2];
			else
				return p[0] | p[1] << 8 | p[2] << 16;
		case 4:
			return *reinterpret_cast<uint32_t*>(p);
		default:
			return 0;       // shouldn't happen, but avoids warnings
		}
	}

	void Surface::fill(uint32_t color)
	{
		SDL_FillRect(surface, nullptr, color);
	}

	void Surface::replace(uint32_t src_color, uint32_t dest_color)
	{
		auto ptr = static_cast<uint32_t*>(surface->pixels);
		auto end = ptr + surface->w * surface->h;
		while (ptr < end)
		{
			if (*ptr == src_color)
				*ptr = dest_color;
			++ptr;
		}
	}

	void Surface::convert_format(uint32_t format)
	{
		auto tmp = SDL_ConvertSurfaceFormat(surface, format, 0);
		if (tmp == nullptr)
		{
			std::stringstream ss;
			ss << "Could not convert surface: " << SDL_GetError();
			throw std::runtime_error(ss.str());
		}
		SDL_FreeSurface(surface);
		surface = tmp;
	}

	void Surface::blend(const Surface& another)
	{
		SDL_BlitSurface(another.surface, nullptr, surface, nullptr);
	}

	void Surface::blend(const Surface& another, const Rect& src, const Rect& dest)
	{
		SDL_BlitSurface(another.surface, (SDL_Rect*)&src, surface, (SDL_Rect*)&dest);
	}

	void Surface::blend(const Surface& another, int x, int y)
	{
		SDL_Rect r{ x, y, another.width(), another.height() };
		SDL_BlitSurface(another.surface, nullptr, surface, &r);
	}

	void Surface::blend_flip_h(const Surface& another, const Rect& src, const Rect& dest)
	{
		Surface tmp_surface(SDL_CreateRGBSurface(0, src.w, src.h, surface->format->BitsPerPixel,
			surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask));
		tmp_surface.blend(*this, src, src);
		tmp_surface.flip_horizontal();
		SDL_BlitSurface(tmp_surface.surface, nullptr, another.surface, (SDL_Rect*)&dest);
	}

	void Surface::blend_flip_v(const Surface& another, const Rect& src, const Rect& dest)
	{
		Surface tmp_surface(SDL_CreateRGBSurface(0, src.w, src.h, surface->format->BitsPerPixel,
			surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask));
		tmp_surface.blend(*this, src, src);
		tmp_surface.flip_vertical();
		SDL_BlitSurface(tmp_surface.surface, nullptr, another.surface, (SDL_Rect*)&dest);
	}

	void Surface::flip_vertical(void) const
	{
		const auto size = surface->w * surface->h;
		switch (surface->format->BytesPerPixel)
		{
		case 1:
			dukat::flip_vertical(static_cast<uint8_t*>(surface->pixels), static_cast<uint8_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 2:
			dukat::flip_vertical(static_cast<uint16_t*>(surface->pixels), static_cast<uint16_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 3:
			dukat::flip_vertical(static_cast<Uint24*>(surface->pixels), static_cast<Uint24*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 4:
			dukat::flip_vertical(static_cast<uint32_t*>(surface->pixels), static_cast<uint32_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		}
	}

	void Surface::flip_horizontal(void) const
	{
		const auto size = surface->w * surface->h;
		switch (surface->format->BytesPerPixel)
		{
		case 1:
			dukat::flip_horizontal(static_cast<uint8_t*>(surface->pixels), static_cast<uint8_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 2:
			dukat::flip_horizontal(static_cast<uint16_t*>(surface->pixels), static_cast<uint16_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 3:
			dukat::flip_horizontal(static_cast<Uint24*>(surface->pixels), static_cast<Uint24*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		case 4:
			dukat::flip_horizontal(static_cast<uint32_t*>(surface->pixels), static_cast<uint32_t*>(surface->pixels) + size, static_cast<size_t>(surface->w));
			break;
		}
	}

	void Surface::apply(const std::function<void(int x, int y, SDL_Surface* s, uint32_t& p)>& f)
	{
		auto ptr = static_cast<uint32_t*>(surface->pixels);
		for (auto y = 0; y < surface->h; y++)
		{
			for (auto x = 0; x < surface->w; x++)
			{
				f(x, y, surface, *(ptr++));
			}
		}
	}

#pragma region Utility Functions

	std::unique_ptr<Surface> load_surface(const std::string& filename)
	{
		auto surface = IMG_Load(filename.c_str());
		if (surface == nullptr)
		{
			std::stringstream ss;
			ss << "Could not load surface: " << filename;
			throw std::runtime_error(ss.str());
		}
		return std::make_unique<Surface>(surface);
	}

	void save_surface(const Surface& surface, const std::string& filename)
	{
		auto res = IMG_SavePNG(surface.get_surface(), filename.c_str());
		sdl_check_result(res, "Save surface");
	}

	void replace_surface_colors(Surface& surface, const std::vector<SDL_Color>& src_colors, const std::vector<SDL_Color>& dest_colors)
	{
		assert(src_colors.size() == dest_colors.size());

		std::unordered_map<uint32_t, uint32_t> colors;
		for (auto i = 0u; i < src_colors.size(); i++)
			colors.insert(std::make_pair(surface.color(src_colors[i]), surface.color(dest_colors[i])));

		auto sfc = surface.get_surface();
		auto ptr = static_cast<uint32_t*>(sfc->pixels);
		auto end = ptr + sfc->w * sfc->h;
		while (ptr < end)
		{
			if (colors.count(*ptr))
				*ptr = colors[*ptr];
			++ptr;
		}
	}

#pragma endregion
}<|endoftext|>


<commit_before>#include <Windows.h>
#include <iostream>
#include <TlHelp32.h>
#include <stdlib.h>
#include <string>

#include "Injection.h"

using namespace std;

/* There are two defined entry points here, one for a  Windows
 * application, and another for a console application.
 *
 * To switch between the two versions, we need to change our
 * subsystem dependency and then rebuild. The compiler will
 * automatically choose the appropriate entry point.
 *
 * To enable Windows (hidden) mode, go to project properties, find the
 * 'linker' section and change the SubSystem option to Windows.
 *
 * To enable console (debugging) mode, go to project properties, find
 * the 'linker' section and change the SubSystem option to Console.
 */

/* Since there are two entry points for this program, we really
 * ought to get to a common point as soon as possible.  This is that
 * common point.
 */
void true_main() {
    // Bootstrapper
    char DllName[MAX_PATH];
    GetCurrentDirectoryA(MAX_PATH, DllName);
    strcat_s(DllName, "\\Bootstrapper.dll");

    DWORD Pid = GetProcessIdByName("GoldWave.exe");
    InjectAndRun(Pid, DllName, "InjectedMain");
}

/* By starting as a Windows application but not displaying any
 * windows, we can become effectively invisible.
 */
#pragma warning(suppress: 28251) // Honeybadger don't care about SAL notation
int __stdcall WinMain (HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int cmdShow)
{
    true_main();
    return 0;
}

/* In any case, it's useful to have a console window visible
 * for debugging purposes.  Use cout to your heart's content!
 */
int main()
{
    true_main();
    return 0;
}
<commit_msg>Change injection target<commit_after>#include <Windows.h>
#include <iostream>
#include <TlHelp32.h>
#include <stdlib.h>
#include <string>

#include "Injection.h"

using namespace std;

/* There are two defined entry points here, one for a  Windows
 * application, and another for a console application.
 *
 * To switch between the two versions, we need to change our
 * subsystem dependency and then rebuild. The compiler will
 * automatically choose the appropriate entry point.
 *
 * To enable Windows (hidden) mode, go to project properties, find the
 * 'linker' section and change the SubSystem option to Windows.
 *
 * To enable console (debugging) mode, go to project properties, find
 * the 'linker' section and change the SubSystem option to Console.
 */

/* Since there are two entry points for this program, we really
 * ought to get to a common point as soon as possible.  This is that
 * common point.
 */
void true_main() {
    // Bootstrapper
    char DllName[MAX_PATH];
    GetCurrentDirectoryA(MAX_PATH, DllName);
    strcat_s(DllName, "\\Bootstrapper.dll");

    DWORD Pid = GetProcessIdByName("halo.exe");
    InjectAndRun(Pid, DllName, "InjectedMain");
}

/* By starting as a Windows application but not displaying any
 * windows, we can become effectively invisible.
 */
#pragma warning(suppress: 28251) // Honeybadger don't care about SAL notation
int __stdcall WinMain (HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int cmdShow)
{
    true_main();
    return 0;
}

/* In any case, it's useful to have a console window visible
 * for debugging purposes.  Use cout to your heart's content!
 */
int main()
{
    true_main();
    return 0;
}
<|endoftext|>


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

#include "mswin.h"

#include "systems.h"
#include "compiler.h"
#include "cramer.h"
#include "graphics.h"
#include "make_system.h"
#include "resources.h"
#include "vector.h"
#include <cstdint>
#include <cstring>

struct triangle_t
{
  float xyz [3] [4]; // Coordinates for single triangle XYZ of Moebius tiling.
  float abc [8] [4]; // Coefficients A, B, C for generator T = AX + BY + CZ.
};

// The fundamental triangle of the tiling has angles
// A = pi/p, B = pi/q, C = pi/r and sides a, b, c.

// By the spherical cosine rule,
// cosa = (cosA + cosB * cosC) / (sinB * sinC),
// cosb = (cosB + cosC * cosA) / (sinC * sinA),
// cosc = (cosC + cosA * cosB) / (sinA * sinB).

// We assume p = 2; thus cosA = 0 and sinA = 1. Therefore,
// cosa = (cosB * cosC) / (sinB * sinC),
// cosb = cosB / sinC,
// cosc = cosC / sinB.

// Any triple (alpha, beta, gamma) identifies a point T relative to
// the spherical triangle XYZ, by the formula
// T = alpha * X + beta * Y + gamma * Z.
// For certain triples, replicating the point T in each triangle
// of the tiling gives the vertices of a uniform polyhedron:

// { 1, 0, 0 },             Point X.
// { 0, 1, 0 },             Point Y.
// { 0, 0, 1 },             Point Z.
// { 0, sinb, sinc },       Intersection of YZ with bisector of angle X.
// { sina, 0, sinc },       Intersection of ZX with bisector of angle Y.
// { sina, sinb, 0 },       Intersection of YZ with bisector of angle Z.
// { sinA, sinB, sinC },    Incentre (intersection of the three bisectors).
// { alpha, beta, gamma },  Snub generator.

//     X1
//    /  \    Part of the tiling of the sphere, showing
//   Y0--Z0   triangles X1-Y0-Z0, X0-Y1-Z0, X0-Y0-Z1.
//   |\  /|
//   | X0 |
//   |/  \|
//   Z1  Y1

// For the snub generator, the three points
//   TX = alpha * X1 + beta * Y0 + gamma * Z0
//   TY = alpha * X0 + beta * Y1 + gamma * Z0
//   TZ = alpha * X0 + beta * Y0 + gamma * Z1
// (see diagram) are the vertices of an equilateral spherical triangle.

const ALIGNED16 triangle_t triangles [3] = {
  // Tetrahedral, <2, 3, 3>.
  {
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f },
      { +0x1.279a74P-1f, +0x1.a20bd8P-1f, +0x0.000000P+0f, 0.0f },
      { +0x1.279a74P-1f, +0x0.000000P+0f, +0x1.a20bd8P-1f, 0.0f },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f }, // 2
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f }, // 1
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f }, // 1
      { +0x0.000000P+0f, +0x1.3988e2P-1f, +0x1.3988e2P-1f, 0.0f }, // 11
      { +0x1.34bf64P-1f, +0x0.000000P+0f, +0x1.0b621eP-1f, 0.0f }, // 6
      { +0x1.34bf64P-1f, +0x1.0b621eP-1f, +0x0.000000P+0f, 0.0f }, // 6
      { +0x1.c9f25cP-2f, +0x1.8c97f0P-2f, +0x1.8c97f0P-2f, 0.0f }, // 7
      { +0x1.4cb7c0P-2f, +0x1.d2393eP-2f, +0x1.d2393eP-2f, 0.0f }, // 4
      // Great icosahedron:
      // { -0x1.605a90P+0f, +0x1.792eceP-1f, +0x1.792eceP-1f, 0.0f },
    },
  },
  // Octahedral, <2, 4, 3>.
  // Oriented so that two octahedral triangles cover one tetrahedral triangle.
  {
    { { +0x1.6a09e6P-1f, +0x1.000000P-1f, +0x1.000000P-1f, 0.0f },
      { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f },
      { +0x1.279a74P-1f, +0x1.a20bd8P-1f, +0x0.000000P+0f, 0.0f },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f }, // 11
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f }, // 2
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f }, // 3
      { +0x0.000000P+0f, +0x1.02ca46P-1f, +0x1.3cf3aeP-1f, 0.0f }, // 13
      { +0x1.1fd4a6P-1f, +0x0.000000P+0f, +0x1.f28990P-2f, 0.0f }, // 8
      { +0x1.43d136P-1f, +0x1.c9f25cP-2f, +0x0.000000P+0f, 0.0f }, // 7
      { +0x1.b9d594P-2f, +0x1.386c8eP-2f, +0x1.7ea3c6P-2f, 0.0f }, // 15
      { +0x1.31816eP-2f, +0x1.8d5502P-2f, +0x1.bdd092P-2f, 0.0f }, // 17
    },
  },
  // Icosahedral, <2, 5, 3>.
  {
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f },
      { +0x1.b38880P-1f, +0x1.0d2ca0P-1f, +0x0.000000P+0f, 0.0f },
      { +0x1.de4bd6P-1f, +0x0.000000P+0f, +0x1.6d62c6P-2f, 0.0f },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f }, // 12
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f }, // 4
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f }, // 5
      { +0x0.000000P+0f, +0x1.b4242aP-2f, +0x1.414c80P-1f, 0.0f }, // 14
      { +0x1.16fc4eP-1f, +0x0.000000P+0f, +0x1.e33798P-2f, 0.0f }, // 10
      { +0x1.4e5014P-1f, +0x1.890220P-2f, +0x0.000000P+0f, 0.0f }, // 9
      { +0x1.b3be36P-2f, +0x1.001f92P-2f, +0x1.795d50P-2f, 0.0f }, // 16
      { +0x1.287f1eP-2f, +0x1.52a52eP-2f, +0x1.b882c6P-2f, 0.0f }, // 18
    },
  },
};

// Turn a PQR triangle into a PRQ triangle.
void reflect (float (& abc) [8] [4],
              float (& xyz) [3] [4])
{
  v4f x = load4f (xyz [0]);
  v4f y = load4f (xyz [1]);
  v4f z = load4f (xyz [2]);

  v4f n = cross (x, y);                  // Perpendicular to x and y.
  v4f d = (dot (n, z) / dot (n, n)) * n; // Component of z parallel to n.

  store4f (xyz [1], z - (d + d));
  store4f (xyz [2], y);

  for (unsigned k = 0; k != 8; ++ k) {
    v4f a = load4f (abc [k]);
    store4f (abc [k], SHUFPS (a, a, (0, 2, 1, 3)));
  }
}

void initialize_systems (float (& abc) [system_count] [8] [4],
  float (& xyz) [system_count] [3] [4], float (& xyzinv) [system_count] [3] [4],
  unsigned (& primitive_count) [system_count],
  unsigned (& vao_ids) [system_count])
{
  ALIGNED16 float nodes [62] [4];
  std::uint8_t indices [60] [6];

  auto init = [&](const triangle_t & t, system_select_t select, unsigned q,
    unsigned r, bool reflected) -> void {

    std::memcpy (xyz [select], t.xyz, sizeof t.xyz);
    std::memcpy (abc [select], t.abc, sizeof t.abc);
    if (reflected) {
      reflect(abc [select], xyz [select]);
    }
    cramer::inverse (xyz [select], xyzinv [select]);
    unsigned N = make_system ({ 2, q, r }, xyz [select], nodes, indices);
    vao_ids [select] = make_vao (N, nodes, indices);
    primitive_count [select] = N;
  };

  for (unsigned n = 0; n != 3; ++ n) {
    init (triangles [n], system_select_t (2 * n + 0), 3 + n, 3, false);
    init (triangles [n], system_select_t (2 * n + 1), 3, 3 + n, true);
  }
}
<commit_msg>systems.cpp (initialize_systems): Simplify.<commit_after>// Copyright 2012-2019 Richard Copley
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "mswin.h"

#include "systems.h"
#include "compiler.h"
#include "cramer.h"
#include "graphics.h"
#include "make_system.h"
#include "resources.h"
#include "vector.h"
#include <cstdint>
#include <cstring>

struct triangle_t
{
  float xyz [3] [4]; // Coordinates for single triangle XYZ of Moebius tiling.
  float abc [8] [4]; // Coefficients A, B, C for generator T = AX + BY + CZ.
};

// The fundamental triangle of the tiling has angles
// A = pi/p, B = pi/q, C = pi/r and sides a, b, c.

// By the spherical cosine rule,
// cosa = (cosA + cosB * cosC) / (sinB * sinC),
// cosb = (cosB + cosC * cosA) / (sinC * sinA),
// cosc = (cosC + cosA * cosB) / (sinA * sinB).

// We assume p = 2; thus cosA = 0 and sinA = 1. Therefore,
// cosa = (cosB * cosC) / (sinB * sinC),
// cosb = cosB / sinC,
// cosc = cosC / sinB.

// Any triple (alpha, beta, gamma) identifies a point T relative to
// the spherical triangle XYZ, by the formula
// T = alpha * X + beta * Y + gamma * Z.
// For certain triples, replicating the point T in each triangle
// of the tiling gives the vertices of a uniform polyhedron:

// { 1, 0, 0 },             Point X.
// { 0, 1, 0 },             Point Y.
// { 0, 0, 1 },             Point Z.
// { 0, sinb, sinc },       Intersection of YZ with bisector of angle X.
// { sina, 0, sinc },       Intersection of ZX with bisector of angle Y.
// { sina, sinb, 0 },       Intersection of YZ with bisector of angle Z.
// { sinA, sinB, sinC },    Incentre (intersection of the three bisectors).
// { alpha, beta, gamma },  Snub generator.

//     X1
//    /  \    Part of the tiling of the sphere, showing
//   Y0--Z0   triangles X1-Y0-Z0, X0-Y1-Z0, X0-Y0-Z1.
//   |\  /|
//   | X0 |
//   |/  \|
//   Z1  Y1

// For the snub generator, the three points
//   TX = alpha * X1 + beta * Y0 + gamma * Z0
//   TY = alpha * X0 + beta * Y1 + gamma * Z0
//   TZ = alpha * X0 + beta * Y0 + gamma * Z1
// (see diagram) are the vertices of an equilateral spherical triangle.

const ALIGNED16 triangle_t triangles [3] = {
  // Tetrahedral, <2, 3, 3>.
  {
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f },
      { +0x1.279a74P-1f, +0x1.a20bd8P-1f, +0x0.000000P+0f, 0.0f },
      { +0x1.279a74P-1f, +0x0.000000P+0f, +0x1.a20bd8P-1f, 0.0f },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f }, // 2
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f }, // 1
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f }, // 1
      { +0x0.000000P+0f, +0x1.3988e2P-1f, +0x1.3988e2P-1f, 0.0f }, // 11
      { +0x1.34bf64P-1f, +0x0.000000P+0f, +0x1.0b621eP-1f, 0.0f }, // 6
      { +0x1.34bf64P-1f, +0x1.0b621eP-1f, +0x0.000000P+0f, 0.0f }, // 6
      { +0x1.c9f25cP-2f, +0x1.8c97f0P-2f, +0x1.8c97f0P-2f, 0.0f }, // 7
      { +0x1.4cb7c0P-2f, +0x1.d2393eP-2f, +0x1.d2393eP-2f, 0.0f }, // 4
      // Great icosahedron:
      // { -0x1.605a90P+0f, +0x1.792eceP-1f, +0x1.792eceP-1f, 0.0f },
    },
  },
  // Octahedral, <2, 4, 3>.
  // Oriented so that two octahedral triangles cover one tetrahedral triangle.
  {
    { { +0x1.6a09e6P-1f, +0x1.000000P-1f, +0x1.000000P-1f, 0.0f },
      { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f },
      { +0x1.279a74P-1f, +0x1.a20bd8P-1f, +0x0.000000P+0f, 0.0f },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f }, // 11
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f }, // 2
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f }, // 3
      { +0x0.000000P+0f, +0x1.02ca46P-1f, +0x1.3cf3aeP-1f, 0.0f }, // 13
      { +0x1.1fd4a6P-1f, +0x0.000000P+0f, +0x1.f28990P-2f, 0.0f }, // 8
      { +0x1.43d136P-1f, +0x1.c9f25cP-2f, +0x0.000000P+0f, 0.0f }, // 7
      { +0x1.b9d594P-2f, +0x1.386c8eP-2f, +0x1.7ea3c6P-2f, 0.0f }, // 15
      { +0x1.31816eP-2f, +0x1.8d5502P-2f, +0x1.bdd092P-2f, 0.0f }, // 17
    },
  },
  // Icosahedral, <2, 5, 3>.
  {
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f },
      { +0x1.b38880P-1f, +0x1.0d2ca0P-1f, +0x0.000000P+0f, 0.0f },
      { +0x1.de4bd6P-1f, +0x0.000000P+0f, +0x1.6d62c6P-2f, 0.0f },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f }, // 12
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f }, // 4
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f }, // 5
      { +0x0.000000P+0f, +0x1.b4242aP-2f, +0x1.414c80P-1f, 0.0f }, // 14
      { +0x1.16fc4eP-1f, +0x0.000000P+0f, +0x1.e33798P-2f, 0.0f }, // 10
      { +0x1.4e5014P-1f, +0x1.890220P-2f, +0x0.000000P+0f, 0.0f }, // 9
      { +0x1.b3be36P-2f, +0x1.001f92P-2f, +0x1.795d50P-2f, 0.0f }, // 16
      { +0x1.287f1eP-2f, +0x1.52a52eP-2f, +0x1.b882c6P-2f, 0.0f }, // 18
    },
  },
};

// Turn a PQR triangle into a PRQ triangle.
void reflect (float (& abc) [8] [4],
              float (& xyz) [3] [4])
{
  v4f x = load4f (xyz [0]);
  v4f y = load4f (xyz [1]);
  v4f z = load4f (xyz [2]);

  v4f n = cross (x, y);                  // Perpendicular to x and y.
  v4f d = (dot (n, z) / dot (n, n)) * n; // Component of z parallel to n.

  store4f (xyz [1], z - (d + d));
  store4f (xyz [2], y);

  for (unsigned k = 0; k != 8; ++ k) {
    v4f a = load4f (abc [k]);
    store4f (abc [k], SHUFPS (a, a, (0, 2, 1, 3)));
  }
}

void initialize_systems (float (& abc) [system_count] [8] [4],
  float (& xyz) [system_count] [3] [4], float (& xyzinv) [system_count] [3] [4],
  unsigned (& primitive_count) [system_count],
  unsigned (& vao_ids) [system_count])
{
  ALIGNED16 float nodes [62] [4];
  std::uint8_t indices [60] [6];

  for (unsigned n = 0; n != 6; ++ n) {
    unsigned p [3] = { 2, 3, 3 };
    p [1 + (n & 1)] = 3 + n / 2;
    std::memcpy (xyz [n], triangles [n / 2].xyz, sizeof triangles [n / 2].xyz);
    std::memcpy (abc [n], triangles [n / 2].abc, sizeof triangles [n / 2].abc);
    if (n & 1) reflect (abc [n], xyz [n]);
    cramer::inverse (xyz [n], xyzinv [n]);
    unsigned N = make_system (p, xyz [n], nodes, indices);
    vao_ids [n] = make_vao (N, nodes, indices);
    primitive_count [n] = N;
  }
}
<|endoftext|>


<commit_before>//===--- Trigram.cpp - Trigram generation for Fuzzy Matching ----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Trigram.h"
#include "../../FuzzyMatch.h"
#include "Token.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include <cctype>
#include <queue>
#include <string>

using namespace llvm;

namespace clang {
namespace clangd {
namespace dex {

/// This is used to mark unigrams and bigrams and distinct them from complete
/// trigrams. Since '$' is not present in valid identifier names, it is safe to
/// use it as the special symbol.
static const char END_MARKER = '$';

std::vector<Token> generateIdentifierTrigrams(llvm::StringRef Identifier) {
  // Apply fuzzy matching text segmentation.
  std::vector<CharRole> Roles(Identifier.size());
  calculateRoles(Identifier,
                 llvm::makeMutableArrayRef(Roles.data(), Identifier.size()));

  std::string LowercaseIdentifier = Identifier.lower();

  // For each character, store indices of the characters to which fuzzy matching
  // algorithm can jump. There are 3 possible variants:
  //
  // * Next Tail - next character from the same segment
  // * Next Head - front character of the next segment
  // * Skip-1-Next Head - front character of the skip-1-next segment
  //
  // Next stores tuples of three indices in the presented order, if a variant is
  // not available then 0 is stored.
  std::vector<std::array<unsigned, 3>> Next(LowercaseIdentifier.size());
  unsigned NextTail = 0, NextHead = 0, NextNextHead = 0;
  // Store two first HEAD characters in the identifier (if present).
  std::deque<char> TwoHeads;
  for (int I = LowercaseIdentifier.size() - 1; I >= 0; --I) {
    Next[I] = {{NextTail, NextHead, NextNextHead}};
    NextTail = Roles[I] == Tail ? I : 0;
    if (Roles[I] == Head) {
      NextNextHead = NextHead;
      NextHead = I;
      TwoHeads.push_front(LowercaseIdentifier[I]);
      if (TwoHeads.size() > 2)
        TwoHeads.pop_back();
    }
  }

  DenseSet<Token> UniqueTrigrams;

  auto add = [&](std::string Chars) {
    UniqueTrigrams.insert(Token(Token::Kind::Trigram, Chars));
  };

  // FIXME(kbobyrev): Instead of producing empty trigram for each identifier,
  // just use True Iterator on the query side when the query string is empty.
  add({{END_MARKER, END_MARKER, END_MARKER}});

  if (TwoHeads.size() == 2)
    add({{TwoHeads.front(), TwoHeads.back(), END_MARKER}});

  if (!LowercaseIdentifier.empty())
    add({{LowercaseIdentifier.front(), END_MARKER, END_MARKER}});

  if (LowercaseIdentifier.size() >= 2)
    add({{LowercaseIdentifier[0], LowercaseIdentifier[1], END_MARKER}});

  if (LowercaseIdentifier.size() >= 3)
    add({{LowercaseIdentifier[0], LowercaseIdentifier[1],
          LowercaseIdentifier[2]}});

  // Iterate through valid seqneces of three characters Fuzzy Matcher can
  // process.
  for (size_t I = 0; I < LowercaseIdentifier.size(); ++I) {
    // Skip delimiters.
    if (Roles[I] != Head && Roles[I] != Tail)
      continue;
    for (const unsigned J : Next[I]) {
      if (!J)
        continue;
      for (const unsigned K : Next[J]) {
        if (!K)
          continue;
        add({{LowercaseIdentifier[I], LowercaseIdentifier[J],
              LowercaseIdentifier[K]}});
      }
    }
  }

  std::vector<Token> Result;
  for (const auto &Trigram : UniqueTrigrams)
    Result.push_back(Trigram);

  return Result;
}

std::vector<Token> generateQueryTrigrams(llvm::StringRef Query) {
  // Apply fuzzy matching text segmentation.
  std::vector<CharRole> Roles(Query.size());
  calculateRoles(Query, llvm::makeMutableArrayRef(Roles.data(), Query.size()));

  // Additional pass is necessary to count valid identifier characters.
  // Depending on that, this function might return incomplete trigram.
  unsigned ValidSymbolsCount = 0;
  for (size_t I = 0; I < Roles.size(); ++I)
    if (Roles[I] == Head || Roles[I] == Tail)
      ++ValidSymbolsCount;

  std::string LowercaseQuery = Query.lower();

  DenseSet<Token> UniqueTrigrams;

  // If the number of symbols which can form fuzzy matching trigram is not
  // sufficient, generate a single incomplete trigram for query.
  if (ValidSymbolsCount < 3) {
    std::string Chars = LowercaseQuery.substr(0, std::min(3UL, Query.size()));
    Chars.append(3 - Chars.size(), END_MARKER);
    UniqueTrigrams.insert(Token(Token::Kind::Trigram, Chars));
  } else {
    std::deque<char> Chars;
    for (size_t I = 0; I < LowercaseQuery.size(); ++I) {
      // If current symbol is delimiter, just skip it.
      if (Roles[I] != Head && Roles[I] != Tail)
        continue;

      Chars.push_back(LowercaseQuery[I]);

      if (Chars.size() > 3)
        Chars.pop_front();

      if (Chars.size() == 3) {
        UniqueTrigrams.insert(
            Token(Token::Kind::Trigram, std::string(begin(Chars), end(Chars))));
      }
    }
  }

  std::vector<Token> Result;
  for (const auto &Trigram : UniqueTrigrams)
    Result.push_back(Trigram);

  return Result;
}

} // namespace dex
} // namespace clangd
} // namespace clang
<commit_msg>Fix MSVC 'std::min: no matching overloaded function found' error.<commit_after>//===--- Trigram.cpp - Trigram generation for Fuzzy Matching ----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Trigram.h"
#include "../../FuzzyMatch.h"
#include "Token.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include <cctype>
#include <queue>
#include <string>

using namespace llvm;

namespace clang {
namespace clangd {
namespace dex {

/// This is used to mark unigrams and bigrams and distinct them from complete
/// trigrams. Since '$' is not present in valid identifier names, it is safe to
/// use it as the special symbol.
static const char END_MARKER = '$';

std::vector<Token> generateIdentifierTrigrams(llvm::StringRef Identifier) {
  // Apply fuzzy matching text segmentation.
  std::vector<CharRole> Roles(Identifier.size());
  calculateRoles(Identifier,
                 llvm::makeMutableArrayRef(Roles.data(), Identifier.size()));

  std::string LowercaseIdentifier = Identifier.lower();

  // For each character, store indices of the characters to which fuzzy matching
  // algorithm can jump. There are 3 possible variants:
  //
  // * Next Tail - next character from the same segment
  // * Next Head - front character of the next segment
  // * Skip-1-Next Head - front character of the skip-1-next segment
  //
  // Next stores tuples of three indices in the presented order, if a variant is
  // not available then 0 is stored.
  std::vector<std::array<unsigned, 3>> Next(LowercaseIdentifier.size());
  unsigned NextTail = 0, NextHead = 0, NextNextHead = 0;
  // Store two first HEAD characters in the identifier (if present).
  std::deque<char> TwoHeads;
  for (int I = LowercaseIdentifier.size() - 1; I >= 0; --I) {
    Next[I] = {{NextTail, NextHead, NextNextHead}};
    NextTail = Roles[I] == Tail ? I : 0;
    if (Roles[I] == Head) {
      NextNextHead = NextHead;
      NextHead = I;
      TwoHeads.push_front(LowercaseIdentifier[I]);
      if (TwoHeads.size() > 2)
        TwoHeads.pop_back();
    }
  }

  DenseSet<Token> UniqueTrigrams;

  auto add = [&](std::string Chars) {
    UniqueTrigrams.insert(Token(Token::Kind::Trigram, Chars));
  };

  // FIXME(kbobyrev): Instead of producing empty trigram for each identifier,
  // just use True Iterator on the query side when the query string is empty.
  add({{END_MARKER, END_MARKER, END_MARKER}});

  if (TwoHeads.size() == 2)
    add({{TwoHeads.front(), TwoHeads.back(), END_MARKER}});

  if (!LowercaseIdentifier.empty())
    add({{LowercaseIdentifier.front(), END_MARKER, END_MARKER}});

  if (LowercaseIdentifier.size() >= 2)
    add({{LowercaseIdentifier[0], LowercaseIdentifier[1], END_MARKER}});

  if (LowercaseIdentifier.size() >= 3)
    add({{LowercaseIdentifier[0], LowercaseIdentifier[1],
          LowercaseIdentifier[2]}});

  // Iterate through valid seqneces of three characters Fuzzy Matcher can
  // process.
  for (size_t I = 0; I < LowercaseIdentifier.size(); ++I) {
    // Skip delimiters.
    if (Roles[I] != Head && Roles[I] != Tail)
      continue;
    for (const unsigned J : Next[I]) {
      if (!J)
        continue;
      for (const unsigned K : Next[J]) {
        if (!K)
          continue;
        add({{LowercaseIdentifier[I], LowercaseIdentifier[J],
              LowercaseIdentifier[K]}});
      }
    }
  }

  std::vector<Token> Result;
  for (const auto &Trigram : UniqueTrigrams)
    Result.push_back(Trigram);

  return Result;
}

std::vector<Token> generateQueryTrigrams(llvm::StringRef Query) {
  // Apply fuzzy matching text segmentation.
  std::vector<CharRole> Roles(Query.size());
  calculateRoles(Query, llvm::makeMutableArrayRef(Roles.data(), Query.size()));

  // Additional pass is necessary to count valid identifier characters.
  // Depending on that, this function might return incomplete trigram.
  unsigned ValidSymbolsCount = 0;
  for (size_t I = 0; I < Roles.size(); ++I)
    if (Roles[I] == Head || Roles[I] == Tail)
      ++ValidSymbolsCount;

  std::string LowercaseQuery = Query.lower();

  DenseSet<Token> UniqueTrigrams;

  // If the number of symbols which can form fuzzy matching trigram is not
  // sufficient, generate a single incomplete trigram for query.
  if (ValidSymbolsCount < 3) {
    std::string Chars =
        LowercaseQuery.substr(0, std::min<size_t>(3UL, Query.size()));
    Chars.append(3 - Chars.size(), END_MARKER);
    UniqueTrigrams.insert(Token(Token::Kind::Trigram, Chars));
  } else {
    std::deque<char> Chars;
    for (size_t I = 0; I < LowercaseQuery.size(); ++I) {
      // If current symbol is delimiter, just skip it.
      if (Roles[I] != Head && Roles[I] != Tail)
        continue;

      Chars.push_back(LowercaseQuery[I]);

      if (Chars.size() > 3)
        Chars.pop_front();

      if (Chars.size() == 3) {
        UniqueTrigrams.insert(
            Token(Token::Kind::Trigram, std::string(begin(Chars), end(Chars))));
      }
    }
  }

  std::vector<Token> Result;
  for (const auto &Trigram : UniqueTrigrams)
    Result.push_back(Trigram);

  return Result;
}

} // namespace dex
} // namespace clangd
} // namespace clang
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/utils/imageProcs/p10_ring_id.H $         */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef _P10_RING_ID_H_
#define _P10_RING_ID_H_

///
/// @enum RingID
/// @brief Master enumeration of all conceivable Ring ID values. These values
///        are used everywhere in Infrastructure codes, ifCompiler,
///        HWPs, Cronus, ipl_customize and ipl_image_tool.

// *****************
// *** IMPORTANT ***
// *****************
// Do  *NOT*  change the numbering, the sequence or add new constants to
// the below enum, unless you know the effect it has on the traversing
// of the TOR ring section:
// - There are hard coded assumptions in SBE and QME PPE codes about the
//   below enums.
// - A change to the below values could cause a co-req situation.
//
enum RingID
{
    // PERV Chiplet Rings - PERV
    perv_fure   = 0, //0x00
    perv_gptr   = 1, //0x01
    perv_lbst   = 2, //0x02
    perv_abst   = 3, //0x03
    perv_repr   = 4, //0x04
    perv_time   = 5, //0x05
    perv_bndy   = 6, //0x06

    // Nest Chiplet Rings - N0
    n0_fure     = 7,  //0x07
    n0_gptr     = 8,  //0x08
    n0_lbst     = 9,  //0x09
    n0_abst     = 10, //0x0A
    n0_repr     = 11, //0x0B
    n0_time     = 12, //0x0C
    n0_bndy     = 13, //0x0D

    // Nest Chiplet Rings - N1
    n1_fure     = 14, //0x0E
    n1_gptr     = 15, //0x0F
    n1_lbst     = 16, //0x10
    n1_abst     = 17, //0x11
    n1_repr     = 18, //0x12
    n1_time     = 19, //0x13
    n1_bndy     = 20, //0x14

    // PCI Chiplet Rings - PCI
    pci_fure    = 21, //0x15
    pci_gptr    = 22, //0x16
    pci_lbst    = 23, //0x17
    pci_abst    = 24, //0x18
    pci_repr    = 25, //0x19
    pci_time    = 26, //0x1A
    pci_bndy    = 27, //0x1B

    // MC Chiplet Rings - MCI
    mc_fure     = 28, //0x1C
    mc_gptr     = 29, //0x1D
    mc_lbst     = 30, //0x1E
    mc_abst     = 31, //0x1F
    mc_repr     = 32, //0x20
    mc_time     = 33, //0x21
    mc_bndy     = 34, //0x22

    // AXON Chiplet Rings - AXON
    iohs_fure   = 35, //0x23
    iohs_gptr   = 36, //0x24
    iohs_lbst   = 37, //0x25
    iohs_abst   = 38, //0x26
    iohs_repr   = 39, //0x27
    iohs_time   = 40, //0x28
    iohs_bndy   = 41, //0x29

    // Quad Chiplet Rings - EQ
    eq_fure     = 42, //0x2A
    eq_gptr     = 43, //0x2B
    eq_lbst     = 44, //0x2C
    eq_abst     = 45, //0x2D
    eq_repr     = 46, //0x2E
    eq_time     = 47, //0x2F
    eq_bndy     = 48, //0x30
    ec_cl2_fure = 49, //0x31
    ec_cl2_gptr = 50, //0x32
    ec_cl2_lbst = 51, //0x33
    ec_cl2_abst = 52, //0x34
    ec_cl2_repr = 53, //0x35
    ec_cl2_time = 54, //0x36
    ec_cl2_bndy = 55, //0x37

    NUM_RING_IDS

}; // enum RingID

#endif  // _P10_RING_ID_H_
<commit_msg>Cache contained PM istep16 ring support<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/utils/imageProcs/p10_ring_id.H $         */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef _P10_RING_ID_H_
#define _P10_RING_ID_H_

///
/// @enum RingID
/// @brief Master enumeration of all conceivable Ring ID values. These values
///        are used everywhere in Infrastructure codes, ifCompiler,
///        HWPs, Cronus, ipl_customize and ipl_image_tool.

// *****************
// *** IMPORTANT ***
// *****************
// Do  *NOT*  change the numbering, the sequence or add new constants to
// the below enum, unless you know the effect it has on the traversing
// of the TOR ring section:
// - There are hard coded assumptions in SBE and QME PPE codes about the
//   below enums.
// - A change to the below values could cause a co-req situation.
//
enum RingID
{
    // PERV Chiplet Rings - PERV
    perv_fure   = 0, //0x00
    perv_gptr   = 1, //0x01
    perv_lbst   = 2, //0x02
    perv_abst   = 3, //0x03
    perv_repr   = 4, //0x04
    perv_time   = 5, //0x05
    perv_bndy   = 6, //0x06

    // Nest Chiplet Rings - N0
    n0_fure     = 7,  //0x07
    n0_gptr     = 8,  //0x08
    n0_lbst     = 9,  //0x09
    n0_abst     = 10, //0x0A
    n0_repr     = 11, //0x0B
    n0_time     = 12, //0x0C
    n0_bndy     = 13, //0x0D

    // Nest Chiplet Rings - N1
    n1_fure     = 14, //0x0E
    n1_gptr     = 15, //0x0F
    n1_lbst     = 16, //0x10
    n1_abst     = 17, //0x11
    n1_repr     = 18, //0x12
    n1_time     = 19, //0x13
    n1_bndy     = 20, //0x14

    // PCI Chiplet Rings - PCI
    pci_fure    = 21, //0x15
    pci_gptr    = 22, //0x16
    pci_lbst    = 23, //0x17
    pci_abst    = 24, //0x18
    pci_repr    = 25, //0x19
    pci_time    = 26, //0x1A
    pci_bndy    = 27, //0x1B

    // MC Chiplet Rings - MCI
    mc_fure     = 28, //0x1C
    mc_gptr     = 29, //0x1D
    mc_lbst     = 30, //0x1E
    mc_abst     = 31, //0x1F
    mc_repr     = 32, //0x20
    mc_time     = 33, //0x21
    mc_bndy     = 34, //0x22

    // AXON Chiplet Rings - AXON
    iohs_fure   = 35, //0x23
    iohs_gptr   = 36, //0x24
    iohs_lbst   = 37, //0x25
    iohs_abst   = 38, //0x26
    iohs_repr   = 39, //0x27
    iohs_time   = 40, //0x28
    iohs_bndy   = 41, //0x29

    // Quad Chiplet Rings - EQ
    eq_fure     = 42, //0x2A
    eq_gptr     = 43, //0x2B
    eq_lbst     = 44, //0x2C
    eq_abst     = 45, //0x2D
    eq_repr     = 46, //0x2E
    eq_time     = 47, //0x2F
    eq_bndy     = 48, //0x30
    ec_cl2_fure = 49, //0x31
    ec_cl2_gptr = 50, //0x32
    ec_cl2_lbst = 51, //0x33
    ec_cl2_abst = 52, //0x34
    ec_cl2_repr = 53, //0x35
    ec_cl2_time = 54, //0x36
    ec_cl2_bndy = 55, //0x37
    ec_mma_fure = 56, //0x38
    ec_l3_fure  = 57, //0x39

    NUM_RING_IDS

}; // enum RingID

#endif  // _P10_RING_ID_H_
<|endoftext|>


<commit_before>#include <errno.h>
#include <netdb.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/errqueue.h>
#include <linux/icmp.h>
#include <sys/socket.h>
#include <sys/time.h>

#include "udpping.h"

namespace
{
    bool getAddress(const QString &address, sockaddr_any *addr)
    {
        struct addrinfo hints;
        struct addrinfo *rp = NULL, *result = NULL;

        memset(&hints, 0, sizeof (hints));
        hints.ai_family = PF_UNSPEC;

        if (getaddrinfo(address.toStdString().c_str(), NULL, &hints, &result))
        {
            return false;
        }

        for (rp = result; rp && rp->ai_family != AF_INET &&
             rp->ai_family != AF_INET6;
             rp = rp->ai_next)
        {
        }

        if (!rp)
        {
            rp = result;
        }

        memcpy(addr, rp->ai_addr, rp->ai_addrlen);

        freeaddrinfo(result);

        return true;
    }

    void randomizePayload(char *payload, const quint32 size)
    {
        char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

        for (quint32 i = 0; i < size; i++)
        {
            payload[i] = chars[qrand() % strlen(chars)];
        }

        if (size > 15)
        {
            // ignore terminating null character
            strncpy(&payload[size - 15], " measure-it.net", 15);
        }
    }
}

UdpPing::UdpPing(QObject *parent)
: Measurement(parent)
, currentStatus(Unknown)
, m_device(NULL)
, m_capture(NULL)
, m_destAddress()
, m_payload(NULL)
{
}

UdpPing::~UdpPing()
{
}

Measurement::Status UdpPing::status() const
{
    return currentStatus;
}

void UdpPing::setStatus(Status status)
{
    if (currentStatus != status)
    {
        currentStatus = status;
        emit statusChanged(status);
    }
}

bool UdpPing::prepare(NetworkManager* networkManager, const MeasurementDefinitionPtr& measurementDefinition)
{
    Q_UNUSED(networkManager);

    definition = measurementDefinition.dynamicCast<UdpPingDefinition>();
    memset(&m_destAddress, 0, sizeof(m_destAddress));

    // resolve
    if (!getAddress(definition->url, &m_destAddress))
    {
        return false;
    }

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        m_destAddress.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        m_destAddress.sin6.sin6_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    }
    else
    {
        // unreachable
        return false;
    }

    return true;
}

bool UdpPing::start()
{
    PingProbe probe;

    // include null-character
    m_payload = new char[definition->payload + 1];
    if (m_payload == NULL)
    {
        return false;
    }
    memset(m_payload, 0, definition->payload + 1);

    setStartDateTime(QDateTime::currentDateTime());

    setStatus(UdpPing::Running);

    memset(&probe, 0, sizeof(probe));
    probe.sock = initSocket();
    if (probe.sock < 0)
    {
        emit error("socket: " + QString(strerror(errno)));
        free(m_payload);
        return false;
    }

    for (quint32 i = 0; i < definition->count; i++)
    {
        ping(&probe);
        m_pingProbes.append(probe);
    }

    close(probe.sock);

    setStatus(UdpPing::Finished);
    free(m_payload);
    emit finished();

    return true;
}

bool UdpPing::stop()
{
    return true;
}

ResultPtr UdpPing::result() const
{
    QVariantList res;

    foreach (const PingProbe &probe, m_pingProbes)
    {
        if (probe.sendTime > 0 && probe.recvTime > 0)
        {
            res << probe.recvTime - probe.sendTime;
        }
    }

    return ResultPtr(new Result(startDateTime(), QDateTime::currentDateTime(), res, QVariant()));
}

int UdpPing::initSocket()
{
    int n = 0;
    int sock = 0;
    int ttl = definition->ttl ? definition->ttl : 64;
    sockaddr_any src_addr;

    memset(&src_addr, 0, sizeof(src_addr));

    sock = socket(m_destAddress.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
    if (sock < 0)
    {
        emit error("socket: " + QString(strerror(errno)));
        return -1;
    }

    src_addr.sa.sa_family = m_destAddress.sa.sa_family;
    if (m_destAddress.sa.sa_family == AF_INET)
    {
        src_addr.sin.sin_port = htons(definition->sourcePort);
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        src_addr.sin6.sin6_port = htons(definition->sourcePort);
    }
    else
    {
        // unreachable
        goto cleanup;
    }

    if (src_addr.sa.sa_family == AF_INET)
    {
        n = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr.sin));
    }
    else if (src_addr.sa.sa_family == AF_INET6)
    {
        n = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr.sin6));
    }
    if (n < 0)
    {
        emit error("bind: " + QString(strerror(errno)));
        goto cleanup;
    }

    n = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &n, sizeof(n)) < 0)
    {
        emit error("setsockopt SOL_TIMESTAMP: " + QString(strerror(errno)));
        goto cleanup;
    }

    // set TTL
    if (setsockopt(sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
    {
        emit error("setsockopt IP_TTL: " + QString(strerror(errno)));
        goto cleanup;
    }

    // use RECVRR
    n = 1;
    if (m_destAddress.sa.sa_family == AF_INET)
    {
        if (setsockopt(sock, SOL_IP, IP_RECVERR, &n, sizeof(n)) < 0)
        {
            emit error("setsockopt IP_RECVERR: " + QString(strerror(errno)));
            goto cleanup;
        }
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVERR, &n, sizeof(n)) < 0)
        {
            emit error("setsockopt IPV6_RECVERR: " + QString(strerror(errno)));
            goto cleanup;
        }
    }
    else
    {
        // unreachable
        goto cleanup;
    }

    return sock;

cleanup:
    close(sock);
    return -1;
}

bool UdpPing::sendData(PingProbe *probe)
{
    int n;
    struct timeval tv;

    memset(&tv, 0, sizeof(tv));
    gettimeofday(&tv, NULL);
    probe->sendTime = tv.tv_sec * 1e6 + tv.tv_usec;

    // randomize payload to prevent caching
    randomizePayload(m_payload, definition->payload);

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        n = sendto(probe->sock, m_payload, definition->payload, 0,
                   (sockaddr *)&m_destAddress, sizeof(m_destAddress.sin));
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        n = sendto(probe->sock, m_payload, definition->payload, 0,
                   (sockaddr *)&m_destAddress, sizeof(m_destAddress.sin6));
    }
    if (n < 0)
    {
        emit error("send: " + QString(strerror(errno)));
        return false;
    }
    return true;
}

void UdpPing::receiveData(PingProbe *probe)
{
    struct msghdr msg;
    sockaddr_any from;
    struct iovec iov;
    char buf[1280];
    char control[1024];
    struct cmsghdr *cm;
    struct sock_extended_err *ee = NULL;

    memset(&msg, 0, sizeof(msg));
    msg.msg_name = &from;
    msg.msg_namelen = sizeof(from);
    msg.msg_control = control;
    msg.msg_controllen = sizeof(control);
    iov.iov_base = buf;
    iov.iov_len = sizeof(buf);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    // poll here
    struct pollfd pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.fd = probe->sock;
    pfd.events = POLLIN | POLLERR;
    if (poll(&pfd, 1, definition->receiveTimeout) < 0)
    {
        emit error("poll: " + QString(strerror(errno)));
        goto cleanup;
    }

    if (!pfd.revents)
    {
        emit timeout(*probe);
        goto cleanup;
    }

    if (recvmsg(probe->sock, &msg, MSG_ERRQUEUE) < 0)
    {
        emit error("recvmsg: " + QString(strerror(errno)));
        goto cleanup;
    }

    for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm))
    {
        void *ptr = CMSG_DATA(cm);

        if (cm->cmsg_level == SOL_SOCKET)
        {

            if (cm->cmsg_type == SO_TIMESTAMP)
            {
                struct timeval *tv = (struct timeval *) ptr;
                probe->recvTime = tv->tv_sec * 1e6 + tv->tv_usec;
            }
        }
        else if (cm->cmsg_level == SOL_IP)
        {
            if (cm->cmsg_type == IP_RECVERR)
            {
                ee = (struct sock_extended_err *) ptr;

                if (ee->ee_origin != SO_EE_ORIGIN_ICMP)
                {
                    ee = NULL;
                    continue;
                }

                if (ee->ee_type == ICMP_SOURCE_QUENCH || ee->ee_type == ICMP_REDIRECT)
                {
                    goto cleanup;
                }
            }
        }
    }
    if (ee)
    {
        memcpy(&probe->source, SO_EE_OFFENDER(ee), sizeof(probe->source));
        if (ee->ee_type == ICMP_TIME_EXCEEDED && ee->ee_code == ICMP_EXC_TTL)
        {
            emit ttlExceeded(*probe);
        } else if (ee->ee_type == ICMP_DEST_UNREACH)
        {
            emit destinationUnreachable(*probe);
        }
    }
cleanup:
    return;
}

void UdpPing::ping(PingProbe *probe)
{
    // send
    if (sendData(probe))
    {
        receiveData(probe);
    }
}

// vim: set sts=4 sw=4 et:
<commit_msg>Missing initialization in udpping<commit_after>#include <errno.h>
#include <netdb.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/errqueue.h>
#include <linux/icmp.h>
#include <sys/socket.h>
#include <sys/time.h>

#include "udpping.h"

namespace
{
    bool getAddress(const QString &address, sockaddr_any *addr)
    {
        struct addrinfo hints;
        struct addrinfo *rp = NULL, *result = NULL;

        memset(&hints, 0, sizeof (hints));
        hints.ai_family = PF_UNSPEC;

        if (getaddrinfo(address.toStdString().c_str(), NULL, &hints, &result))
        {
            return false;
        }

        for (rp = result; rp && rp->ai_family != AF_INET &&
             rp->ai_family != AF_INET6;
             rp = rp->ai_next)
        {
        }

        if (!rp)
        {
            rp = result;
        }

        memcpy(addr, rp->ai_addr, rp->ai_addrlen);

        freeaddrinfo(result);

        return true;
    }

    void randomizePayload(char *payload, const quint32 size)
    {
        char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

        for (quint32 i = 0; i < size; i++)
        {
            payload[i] = chars[qrand() % strlen(chars)];
        }

        if (size > 15)
        {
            // ignore terminating null character
            strncpy(&payload[size - 15], " measure-it.net", 15);
        }
    }
}

UdpPing::UdpPing(QObject *parent)
: Measurement(parent)
, currentStatus(Unknown)
, m_device(NULL)
, m_capture(NULL)
, m_destAddress()
, m_payload(NULL)
{
}

UdpPing::~UdpPing()
{
}

Measurement::Status UdpPing::status() const
{
    return currentStatus;
}

void UdpPing::setStatus(Status status)
{
    if (currentStatus != status)
    {
        currentStatus = status;
        emit statusChanged(status);
    }
}

bool UdpPing::prepare(NetworkManager* networkManager, const MeasurementDefinitionPtr& measurementDefinition)
{
    Q_UNUSED(networkManager);

    definition = measurementDefinition.dynamicCast<UdpPingDefinition>();
    memset(&m_destAddress, 0, sizeof(m_destAddress));

    // resolve
    if (!getAddress(definition->url, &m_destAddress))
    {
        return false;
    }

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        m_destAddress.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        m_destAddress.sin6.sin6_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    }
    else
    {
        // unreachable
        return false;
    }

    return true;
}

bool UdpPing::start()
{
    PingProbe probe;

    // include null-character
    m_payload = new char[definition->payload + 1];
    if (m_payload == NULL)
    {
        return false;
    }
    memset(m_payload, 0, definition->payload + 1);

    setStartDateTime(QDateTime::currentDateTime());

    setStatus(UdpPing::Running);

    memset(&probe, 0, sizeof(probe));
    probe.sock = initSocket();
    if (probe.sock < 0)
    {
        emit error("socket: " + QString(strerror(errno)));
        free(m_payload);
        return false;
    }

    for (quint32 i = 0; i < definition->count; i++)
    {
        ping(&probe);
        m_pingProbes.append(probe);
    }

    close(probe.sock);

    setStatus(UdpPing::Finished);
    free(m_payload);
    emit finished();

    return true;
}

bool UdpPing::stop()
{
    return true;
}

ResultPtr UdpPing::result() const
{
    QVariantList res;

    foreach (const PingProbe &probe, m_pingProbes)
    {
        if (probe.sendTime > 0 && probe.recvTime > 0)
        {
            res << probe.recvTime - probe.sendTime;
        }
    }

    return ResultPtr(new Result(startDateTime(), QDateTime::currentDateTime(), res, QVariant()));
}

int UdpPing::initSocket()
{
    int n = 0;
    int sock = 0;
    int ttl = definition->ttl ? definition->ttl : 64;
    sockaddr_any src_addr;

    memset(&src_addr, 0, sizeof(src_addr));

    sock = socket(m_destAddress.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
    if (sock < 0)
    {
        emit error("socket: " + QString(strerror(errno)));
        return -1;
    }

    src_addr.sa.sa_family = m_destAddress.sa.sa_family;
    if (m_destAddress.sa.sa_family == AF_INET)
    {
        src_addr.sin.sin_port = htons(definition->sourcePort);
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        src_addr.sin6.sin6_port = htons(definition->sourcePort);
    }
    else
    {
        // unreachable
        goto cleanup;
    }

    if (src_addr.sa.sa_family == AF_INET)
    {
        n = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr.sin));
    }
    else if (src_addr.sa.sa_family == AF_INET6)
    {
        n = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr.sin6));
    }
    if (n < 0)
    {
        emit error("bind: " + QString(strerror(errno)));
        goto cleanup;
    }

    n = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &n, sizeof(n)) < 0)
    {
        emit error("setsockopt SOL_TIMESTAMP: " + QString(strerror(errno)));
        goto cleanup;
    }

    // set TTL
    if (setsockopt(sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
    {
        emit error("setsockopt IP_TTL: " + QString(strerror(errno)));
        goto cleanup;
    }

    // use RECVRR
    n = 1;
    if (m_destAddress.sa.sa_family == AF_INET)
    {
        if (setsockopt(sock, SOL_IP, IP_RECVERR, &n, sizeof(n)) < 0)
        {
            emit error("setsockopt IP_RECVERR: " + QString(strerror(errno)));
            goto cleanup;
        }
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVERR, &n, sizeof(n)) < 0)
        {
            emit error("setsockopt IPV6_RECVERR: " + QString(strerror(errno)));
            goto cleanup;
        }
    }
    else
    {
        // unreachable
        goto cleanup;
    }

    return sock;

cleanup:
    close(sock);
    return -1;
}

bool UdpPing::sendData(PingProbe *probe)
{
    int n = 0;
    struct timeval tv;

    memset(&tv, 0, sizeof(tv));
    gettimeofday(&tv, NULL);
    probe->sendTime = tv.tv_sec * 1e6 + tv.tv_usec;

    // randomize payload to prevent caching
    randomizePayload(m_payload, definition->payload);

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        n = sendto(probe->sock, m_payload, definition->payload, 0,
                   (sockaddr *)&m_destAddress, sizeof(m_destAddress.sin));
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        n = sendto(probe->sock, m_payload, definition->payload, 0,
                   (sockaddr *)&m_destAddress, sizeof(m_destAddress.sin6));
    }
    if (n < 0)
    {
        emit error("send: " + QString(strerror(errno)));
        return false;
    }
    return true;
}

void UdpPing::receiveData(PingProbe *probe)
{
    struct msghdr msg;
    sockaddr_any from;
    struct iovec iov;
    char buf[1280];
    char control[1024];
    struct cmsghdr *cm;
    struct sock_extended_err *ee = NULL;

    memset(&msg, 0, sizeof(msg));
    msg.msg_name = &from;
    msg.msg_namelen = sizeof(from);
    msg.msg_control = control;
    msg.msg_controllen = sizeof(control);
    iov.iov_base = buf;
    iov.iov_len = sizeof(buf);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    // poll here
    struct pollfd pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.fd = probe->sock;
    pfd.events = POLLIN | POLLERR;
    if (poll(&pfd, 1, definition->receiveTimeout) < 0)
    {
        emit error("poll: " + QString(strerror(errno)));
        goto cleanup;
    }

    if (!pfd.revents)
    {
        emit timeout(*probe);
        goto cleanup;
    }

    if (recvmsg(probe->sock, &msg, MSG_ERRQUEUE) < 0)
    {
        emit error("recvmsg: " + QString(strerror(errno)));
        goto cleanup;
    }

    for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm))
    {
        void *ptr = CMSG_DATA(cm);

        if (cm->cmsg_level == SOL_SOCKET)
        {

            if (cm->cmsg_type == SO_TIMESTAMP)
            {
                struct timeval *tv = (struct timeval *) ptr;
                probe->recvTime = tv->tv_sec * 1e6 + tv->tv_usec;
            }
        }
        else if (cm->cmsg_level == SOL_IP)
        {
            if (cm->cmsg_type == IP_RECVERR)
            {
                ee = (struct sock_extended_err *) ptr;

                if (ee->ee_origin != SO_EE_ORIGIN_ICMP)
                {
                    ee = NULL;
                    continue;
                }

                if (ee->ee_type == ICMP_SOURCE_QUENCH || ee->ee_type == ICMP_REDIRECT)
                {
                    goto cleanup;
                }
            }
        }
    }
    if (ee)
    {
        memcpy(&probe->source, SO_EE_OFFENDER(ee), sizeof(probe->source));
        if (ee->ee_type == ICMP_TIME_EXCEEDED && ee->ee_code == ICMP_EXC_TTL)
        {
            emit ttlExceeded(*probe);
        } else if (ee->ee_type == ICMP_DEST_UNREACH)
        {
            emit destinationUnreachable(*probe);
        }
    }
cleanup:
    return;
}

void UdpPing::ping(PingProbe *probe)
{
    // send
    if (sendData(probe))
    {
        receiveData(probe);
    }
}

// vim: set sts=4 sw=4 et:
<|endoftext|>


<commit_before>/*
 * MacFileMonitor.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/system/FileMonitor.hpp>

#include <CoreServices/CoreServices.h>

#include <boost/foreach.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <core/Log.hpp>
#include <core/Error.hpp>
#include <core/FileInfo.hpp>
#include <core/Thread.hpp>

#include <core/system/FileScanner.hpp>
#include <core/system/System.hpp>

#include "FileMonitorImpl.hpp"

namespace rstudio {
namespace core {
namespace system {
namespace file_monitor {

namespace {

class FileEventContext : boost::noncopyable
{
public:
   FileEventContext()
      : streamRef(NULL), recursive(false)
   {
      handle = Handle((void*)this);
   }
   virtual ~FileEventContext() {}
   Handle handle;
   FSEventStreamRef streamRef;
   FilePath rootPath;
   bool recursive;
   boost::function<bool(const FileInfo&)> filter;
   tree<FileInfo> fileTree;
   Callbacks callbacks;
};

void fileEventCallback(ConstFSEventStreamRef streamRef,
                       void *pCallbackInfo,
                       size_t numEvents,
                       void *eventPaths,
                       const FSEventStreamEventFlags eventFlags[],
                       const FSEventStreamEventId eventIds[])
{
   // get context
   FileEventContext* pContext = (FileEventContext*)pCallbackInfo;

   // bail if we don't have callbacks (we wouldn't if a callback snuck
   // through to us even after we failed to fully initialize the file monitor
   // (e.g. if there was an error during file listing)
   if (!pContext->callbacks.onFilesChanged)
      return;

   char **paths = (char**)eventPaths;
   for (std::size_t i=0; i<numEvents; i++)
   {
      // check for root changed (unregister)
      if (eventFlags[i] & kFSEventStreamEventFlagRootChanged)
      {
         // propagate error to client
         Error error = fileNotFoundError(pContext->rootPath.absolutePath(),
                                         ERROR_LOCATION);
         pContext->callbacks.onMonitoringError(error);

         // unregister this monitor (this is done via postback from the
         // main file_monitor loop so that the monitor Handle can be tracked)
         file_monitor::unregisterMonitor(pContext->handle);

         return;
      }

      // make a copy of the path and strip off trailing / if necessary
      std::string path(paths[i]);
      boost::algorithm::trim_right_if(path, boost::algorithm::is_any_of("/"));

      // if we aren't in recursive mode then ignore this if it isn't for
      // the root directory
      if (!pContext->recursive && (path != pContext->rootPath.absolutePath()))
         continue;

      // get FileInfo for this directory
      FileInfo fileInfo(path, true);

      // apply the filter (if any)
      if (!pContext->filter || pContext->filter(fileInfo))
      {
         // check for need to do recursive scan
         bool recursive = pContext->recursive &&
                          (eventFlags[i] & kFSEventStreamEventFlagMustScanSubDirs);

         // process changes
         Error error = impl::discoverAndProcessFileChanges(
                                             fileInfo,
                                             recursive,
                                             pContext->filter,
                                             &(pContext->fileTree),
                                             pContext->callbacks.onFilesChanged);
         if (error &&
            (error.code() != boost::system::errc::no_such_file_or_directory))
         {
            LOG_ERROR(error);
         }
      }
   }
}

class CFRefScope : boost::noncopyable
{
public:
   explicit CFRefScope(CFTypeRef ref)
      : ref_(ref)
   {
   }
   virtual ~CFRefScope()
   {
      try
      {
         ::CFRelease(ref_);
      }
      catch(...)
      {
      }
   }
private:
   CFTypeRef ref_;
};

void invalidateAndReleaseEventStream(FSEventStreamRef streamRef)
{
   ::FSEventStreamInvalidate(streamRef);
   ::FSEventStreamRelease(streamRef);
}

void stopInvalidateAndReleaseEventStream(FSEventStreamRef streamRef)
{
   ::FSEventStreamStop(streamRef);
   invalidateAndReleaseEventStream(streamRef);
}

} // anonymous namespace

namespace detail {

// register a new file monitor
Handle registerMonitor(const FilePath& filePath,
                       bool recursive,
                       const boost::function<bool(const FileInfo&)>& filter,
                       const Callbacks& callbacks)
{
   // allocate file path
   CFStringRef filePathRef = ::CFStringCreateWithCString(
                                       kCFAllocatorDefault,
                                       filePath.absolutePath().c_str(),
                                       kCFStringEncodingUTF8);
   if (filePathRef == NULL)
   {
      callbacks.onRegistrationError(systemError(
                                       boost::system::errc::not_enough_memory,
                                       ERROR_LOCATION));
      return Handle();
   }
   CFRefScope filePathRefScope(filePathRef);

   // allocate paths array
   CFArrayRef pathsArrayRef = ::CFArrayCreate(kCFAllocatorDefault,
                                              (const void **)&filePathRef,
                                              1,
                                              NULL);
   if (pathsArrayRef == NULL)
   {
      callbacks.onRegistrationError(systemError(
                                       boost::system::errc::not_enough_memory,
                                       ERROR_LOCATION));
      return Handle();
   }
   CFRefScope pathsArrayRefScope(pathsArrayRef);

   // create and allocate FileEventContext (create auto-ptr in case we
   // return early, we'll call release later before returning)
   FileEventContext* pContext = new FileEventContext();
   pContext->rootPath = filePath;
   pContext->recursive = recursive;
   pContext->filter = filter;
   std::auto_ptr<FileEventContext> autoPtrContext(pContext);
   FSEventStreamContext context;
   context.version = 0;
   context.info = (void*) pContext;
   context.retain = NULL;
   context.release = NULL;
   context.copyDescription = NULL;

   // create the stream and save a reference to it
   pContext->streamRef = ::FSEventStreamCreate(
                  kCFAllocatorDefault,
                  &fileEventCallback,
                  &context,
                  pathsArrayRef,
                  kFSEventStreamEventIdSinceNow,
                  1,
                  kFSEventStreamCreateFlagNoDefer |
                  kFSEventStreamCreateFlagWatchRoot);
   if (pContext->streamRef == NULL)
   {
      callbacks.onRegistrationError(systemError(
                                       boost::system::errc::no_stream_resources,
                                       ERROR_LOCATION));
      return Handle();
   }

   // schedule with the run loop
   ::FSEventStreamScheduleWithRunLoop(pContext->streamRef,
                                      ::CFRunLoopGetCurrent(),
                                      kCFRunLoopDefaultMode);

   // start the event stream (check for errors and release if necessary
   if (!::FSEventStreamStart(pContext->streamRef))
   {
      invalidateAndReleaseEventStream(pContext->streamRef);

      callbacks.onRegistrationError(systemError(
                                       boost::system::errc::no_stream_resources,
                                       ERROR_LOCATION));
      return Handle();
   }

   // scan the files
   core::system::FileScannerOptions options;
   options.recursive = recursive;
   options.yield = true;
   options.filter = filter;
   Error error = scanFiles(FileInfo(filePath), options, &pContext->fileTree);
   if (error)
   {
       // stop, invalidate, release
       stopInvalidateAndReleaseEventStream(pContext->streamRef);

       // return error
       callbacks.onRegistrationError(error);
       return Handle();
   }

   // now that we have finished the file listing we know we have a valid
   // file-monitor so set the callbacks
   pContext->callbacks = callbacks;

   // we are going to pass the context pointer to the client (as the Handle)
   // so we release it here to relinquish ownership
   autoPtrContext.release();

   // notify the caller that we have successfully registered
   callbacks.onRegistered(pContext->handle, pContext->fileTree);

   // return the handle
   return pContext->handle;
}

// unregister a file monitor
void unregisterMonitor(Handle handle)
{
   // cast to context
   FileEventContext* pContext = (FileEventContext*)(handle.pData);

   // stop, invalidate, release
   stopInvalidateAndReleaseEventStream(pContext->streamRef);

   // let the client know we are unregistered (note this call should always
   // be prior to delete pContext below!)
   pContext->callbacks.onUnregistered(handle);

   // delete the context
   delete pContext;
}

void run(const boost::function<void()>& checkForInput)
{
   // ensure we have a run loop for this thread (not sure if this is
   // strictly necessary but it is not harmful)
   ::CFRunLoopGetCurrent();

   while (true)
   {
      // check the run loop
      SInt32 reason = ::CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);

      // if we handled a source then run again
      if (reason == kCFRunLoopRunHandledSource)
      {
         continue;
      }

      else if (reason == kCFRunLoopRunStopped)
      {
         LOG_WARNING_MESSAGE("Unexpected stop of file monitor run loop");
         break;
      }

      // check for input
      checkForInput();
   }
}

void stop()
{
   // no need to call CFRunLoopStop(CFRunLoopGetCurrent()) because control
   // is already outside of the run loop logic (above).
}

} // namespace detail
} // namespace file_monitor
} // namespace system
} // namespace core
} // namespace rstudio

<commit_msg>guard against spurious root-changed FS events<commit_after>/*
 * MacFileMonitor.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/system/FileMonitor.hpp>

#include <CoreServices/CoreServices.h>

#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <core/Log.hpp>
#include <core/Error.hpp>
#include <core/FileInfo.hpp>
#include <core/Thread.hpp>

#include <core/system/FileScanner.hpp>
#include <core/system/System.hpp>

#include "FileMonitorImpl.hpp"

namespace rstudio {
namespace core {
namespace system {
namespace file_monitor {

namespace {

class DirectoryHandle : boost::noncopyable
{
public:
   DirectoryHandle(const std::string& path)
      : fd_(-1)
   {
      const char* cpath = path.c_str();
      auto f = [&]() { return ::open(cpath, O_DIRECTORY); };
      Error error = posixCall<int>(f, ERROR_LOCATION, &fd_);
      if (error)
         LOG_ERROR(error);
   }

   ~DirectoryHandle()
   {
      if (fd_ != -1)
      {
         auto f = [&]() { return ::close(fd_); };
         safePosixCall<int>(f, ERROR_LOCATION);
      }
   }

   FilePath currentPath()
   {
      // read the path associated with the descriptor
      char path[PATH_MAX];
      auto f = [&]() { return ::fcntl(fd_, F_GETPATH, path); };
      Error error = posixCall<int>(f, ERROR_LOCATION);
      if (error)
         return FilePath();

      // validate the directory still exists
      FilePath currPath(path);
      if (!currPath.isDirectory())
         return FilePath();

      // okay, return the path
      return currPath;
   }

private:
   int fd_;
};

class FileEventContext : boost::noncopyable
{
public:
   FileEventContext(const FilePath& rootPath)
      : rootPath(rootPath),
        rootHandle(rootPath.absolutePathNative()),
        streamRef(nullptr),
        recursive(false)
   {
      handle = Handle((void*)this);
   }

   virtual ~FileEventContext()
   {
   }

   Handle handle;
   FilePath rootPath;
   DirectoryHandle rootHandle;
   FSEventStreamRef streamRef;
   bool recursive;
   boost::function<bool(const FileInfo&)> filter;
   tree<FileInfo> fileTree;
   Callbacks callbacks;
};

void fileEventCallback(ConstFSEventStreamRef streamRef,
                       void *pCallbackInfo,
                       size_t numEvents,
                       void *eventPaths,
                       const FSEventStreamEventFlags eventFlags[],
                       const FSEventStreamEventId eventIds[])
{
   // get context
   FileEventContext* pContext = (FileEventContext*)pCallbackInfo;

   // bail if we don't have callbacks (we wouldn't if a callback snuck
   // through to us even after we failed to fully initialize the file monitor
   // (e.g. if there was an error during file listing)
   if (!pContext->callbacks.onFilesChanged)
      return;

   // de-register the file monitor if the root path has changed or been
   // removed
   //
   // NOTE: on macOS Catalina, we observed spurious 'RootChanged' events
   // delivered causing the file monitor to erroneously detach. protect
   // against this by also double-checking whether the original path
   // monitored and the path reported by the file handle match up
   //
   // https://github.com/rstudio/rstudio/issues/4755
   if (pContext->rootPath != pContext->rootHandle.currentPath())
   {
      // propagate error to client
      Error error = fileNotFoundError(pContext->rootPath.absolutePath(),
                                      ERROR_LOCATION);
      pContext->callbacks.onMonitoringError(error);

      // unregister this monitor (this is done via postback from the
      // main file_monitor loop so that the monitor Handle can be tracked)
      file_monitor::unregisterMonitor(pContext->handle);

      return;
   }

   char **paths = (char**) eventPaths;
   for (std::size_t i = 0; i < numEvents; i++)
   {
      // make a copy of the path and strip off trailing / if necessary
      std::string path(paths[i]);
      boost::algorithm::trim_right_if(path, boost::algorithm::is_any_of("/"));

      // if we aren't in recursive mode then ignore this if it isn't for
      // the root directory
      if (!pContext->recursive && (path != pContext->rootPath.absolutePath()))
         continue;

      // get FileInfo for this directory
      FileInfo fileInfo(path, true);

      // apply the filter (if any)
      if (!pContext->filter || pContext->filter(fileInfo))
      {
         // check for need to do recursive scan
         bool recursive = pContext->recursive &&
                          (eventFlags[i] & kFSEventStreamEventFlagMustScanSubDirs);

         // process changes
         Error error = impl::discoverAndProcessFileChanges(
                                             fileInfo,
                                             recursive,
                                             pContext->filter,
                                             &(pContext->fileTree),
                                             pContext->callbacks.onFilesChanged);
         if (error &&
            (error.code() != boost::system::errc::no_such_file_or_directory))
         {
            LOG_ERROR(error);
         }
      }
   }
}

class CFRefScope : boost::noncopyable
{
public:
   explicit CFRefScope(CFTypeRef ref)
      : ref_(ref)
   {
   }
   virtual ~CFRefScope()
   {
      try
      {
         ::CFRelease(ref_);
      }
      catch(...)
      {
      }
   }
private:
   CFTypeRef ref_;
};

void invalidateAndReleaseEventStream(FSEventStreamRef streamRef)
{
   ::FSEventStreamInvalidate(streamRef);
   ::FSEventStreamRelease(streamRef);
}

void stopInvalidateAndReleaseEventStream(FSEventStreamRef streamRef)
{
   ::FSEventStreamStop(streamRef);
   invalidateAndReleaseEventStream(streamRef);
}

} // anonymous namespace

namespace detail {

// register a new file monitor
Handle registerMonitor(const FilePath& filePath,
                       bool recursive,
                       const boost::function<bool(const FileInfo&)>& filter,
                       const Callbacks& callbacks)
{
   // allocate file path
   CFStringRef filePathRef = ::CFStringCreateWithCString(
                                       kCFAllocatorDefault,
                                       filePath.absolutePath().c_str(),
                                       kCFStringEncodingUTF8);
   if (filePathRef == NULL)
   {
      callbacks.onRegistrationError(systemError(
                                       boost::system::errc::not_enough_memory,
                                       ERROR_LOCATION));
      return Handle();
   }
   CFRefScope filePathRefScope(filePathRef);

   // allocate paths array
   CFArrayRef pathsArrayRef = ::CFArrayCreate(kCFAllocatorDefault,
                                              (const void **)&filePathRef,
                                              1,
                                              NULL);
   if (pathsArrayRef == NULL)
   {
      callbacks.onRegistrationError(systemError(
                                       boost::system::errc::not_enough_memory,
                                       ERROR_LOCATION));
      return Handle();
   }
   CFRefScope pathsArrayRefScope(pathsArrayRef);

   // create and allocate FileEventContext (create auto-ptr in case we
   // return early, we'll call release later before returning)
   FileEventContext* pContext = new FileEventContext(filePath);
   pContext->recursive = recursive;
   pContext->filter = filter;
   std::unique_ptr<FileEventContext> autoPtrContext(pContext);
   FSEventStreamContext context;
   context.version = 0;
   context.info = (void*) pContext;
   context.retain = NULL;
   context.release = NULL;
   context.copyDescription = NULL;

   // create the stream and save a reference to it
   pContext->streamRef = ::FSEventStreamCreate(
                  kCFAllocatorDefault,
                  &fileEventCallback,
                  &context,
                  pathsArrayRef,
                  kFSEventStreamEventIdSinceNow,
                  1,
                  kFSEventStreamCreateFlagNoDefer |
                  kFSEventStreamCreateFlagWatchRoot);
   if (pContext->streamRef == NULL)
   {
      callbacks.onRegistrationError(systemError(
                                       boost::system::errc::no_stream_resources,
                                       ERROR_LOCATION));
      return Handle();
   }

   // schedule with the run loop
   ::FSEventStreamScheduleWithRunLoop(pContext->streamRef,
                                      ::CFRunLoopGetCurrent(),
                                      kCFRunLoopDefaultMode);

   // start the event stream (check for errors and release if necessary
   if (!::FSEventStreamStart(pContext->streamRef))
   {
      invalidateAndReleaseEventStream(pContext->streamRef);

      callbacks.onRegistrationError(systemError(
                                       boost::system::errc::no_stream_resources,
                                       ERROR_LOCATION));
      return Handle();
   }

   // scan the files
   core::system::FileScannerOptions options;
   options.recursive = recursive;
   options.yield = true;
   options.filter = filter;
   Error error = scanFiles(FileInfo(filePath), options, &pContext->fileTree);
   if (error)
   {
       // stop, invalidate, release
       stopInvalidateAndReleaseEventStream(pContext->streamRef);

       // return error
       callbacks.onRegistrationError(error);
       return Handle();
   }

   // now that we have finished the file listing we know we have a valid
   // file-monitor so set the callbacks
   pContext->callbacks = callbacks;

   // we are going to pass the context pointer to the client (as the Handle)
   // so we release it here to relinquish ownership
   autoPtrContext.release();

   // notify the caller that we have successfully registered
   callbacks.onRegistered(pContext->handle, pContext->fileTree);

   // return the handle
   return pContext->handle;
}

// unregister a file monitor
void unregisterMonitor(Handle handle)
{
   // cast to context
   FileEventContext* pContext = (FileEventContext*)(handle.pData);

   // stop, invalidate, release
   stopInvalidateAndReleaseEventStream(pContext->streamRef);

   // let the client know we are unregistered (note this call should always
   // be prior to delete pContext below!)
   pContext->callbacks.onUnregistered(handle);

   // delete the context
   delete pContext;
}

void run(const boost::function<void()>& checkForInput)
{
   // ensure we have a run loop for this thread (not sure if this is
   // strictly necessary but it is not harmful)
   ::CFRunLoopGetCurrent();

   while (true)
   {
      // check the run loop
      SInt32 reason = ::CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);

      // if we handled a source then run again
      if (reason == kCFRunLoopRunHandledSource)
      {
         continue;
      }

      else if (reason == kCFRunLoopRunStopped)
      {
         LOG_WARNING_MESSAGE("Unexpected stop of file monitor run loop");
         break;
      }

      // check for input
      checkForInput();
   }
}

void stop()
{
   // no need to call CFRunLoopStop(CFRunLoopGetCurrent()) because control
   // is already outside of the run loop logic (above).
}

} // namespace detail
} // namespace file_monitor
} // namespace system
} // namespace core
} // namespace rstudio

<|endoftext|>