<commit_before>#include <silicium/tcp_acceptor.hpp>
#include <silicium/coroutine.hpp>
#include <silicium/total_consumer.hpp>
#include <silicium/flatten.hpp>
#include <silicium/socket_observable.hpp>
#include <silicium/sending_observable.hpp>
#include <silicium/received_from_socket_source.hpp>
#include <silicium/observable_source.hpp>
#include <silicium/optional.hpp>
#include <silicium/http/http.hpp>
#include <boost/interprocess/sync/null_mutex.hpp>
#include <boost/container/string.hpp>
#include <boost/unordered_map.hpp>

namespace
{
	using response_part = Si::incoming_bytes;

	boost::iterator_range<char const *> to_range(response_part part)
	{
		return boost::make_iterator_range(part.begin, part.end);
	}

	using byte = boost::uint8_t;
	using digest = boost::container::basic_string<byte>;

	struct content_request
	{
		digest requested_file;
	};

	Si::optional<unsigned char> decode_ascii_hex_digit(char digit)
	{
		switch (digit)
		{
		case '0': return 0;
		case '1': return 1;
		case '2': return 2;
		case '3': return 3;
		case '4': return 4;
		case '5': return 5;
		case '6': return 6;
		case '7': return 7;
		case '8': return 8;
		case '9': return 9;
		case 'a': case 'A': return 10;
		case 'b': case 'B': return 11;
		case 'c': case 'C': return 12;
		case 'd': case 'D': return 13;
		case 'e': case 'E': return 14;
		case 'f': case 'F': return 15;
		default:
			return Si::none;
		}
	}

	template <class InputIterator, class OutputIterator>
	std::pair<InputIterator, OutputIterator> decode_ascii_hex_bytes(InputIterator begin, InputIterator end, OutputIterator bytes)
	{
		for (;;)
		{
			if (begin == end)
			{
				break;
			}
			char const first_char = *begin;
			Si::optional<unsigned char> const first = decode_ascii_hex_digit(first_char);
			if (!first)
			{
				break;
			}
			auto const next = begin + 1;
			if (next == end)
			{
				break;
			}
			char const second_char = *next;
			Si::optional<unsigned char> const second = decode_ascii_hex_digit(second_char);
			if (!second)
			{
				break;
			}
			begin = next + 1;
			unsigned char const digit = static_cast<unsigned char>((*first * 16) + *second);
			*bytes = digit;
			++bytes;
		}
		return std::make_pair(begin, bytes);
	}

	Si::optional<content_request> parse_request_path(std::string const &path)
	{
		if (path.empty())
		{
			return Si::none;
		}
		auto digest_begin = path.begin();
		if (*digest_begin == '/')
		{
			++digest_begin;
		}
		content_request request;
		auto const rest = decode_ascii_hex_bytes(digest_begin, path.end(), std::back_inserter(request.requested_file));
		if (rest.first != path.end())
		{
			return Si::none;
		}
		return std::move(request);
	}

	struct file_system_location
	{
		//unique_ptr for noexcept-movability
		std::unique_ptr<boost::filesystem::path> where;
	};

	using location = Si::fast_variant<file_system_location>;

	struct file_repository
	{
		boost::unordered_map<digest, location> available;

		location const *find_location(digest const &key) const
		{
			auto i = available.find(key);
			return (i == end(available)) ? nullptr : &i->second;
		}
	};

	template <class ReceiveObservable, class MakeSender, class Shutdown>
	void serve_client(
		Si::yield_context<Si::nothing> &yield,
		ReceiveObservable &receive,
		MakeSender const &make_sender,
		Shutdown const &shutdown,
		file_repository const &repository)
	{
		auto receive_sync = Si::make_observable_source(Si::ref(receive), yield);
		Si::received_from_socket_source receive_bytes(receive_sync);
		auto header = Si::http::parse_header(receive_bytes);
		if (!header)
		{
			return;
		}

		auto const request = parse_request_path(header->path);
		if (!request)
		{
			//TODO: 404 or sth
			return;
		}

		location const * const found_file = repository.find_location(request->requested_file);
		if (!found_file)
		{
			//TODO: 404
			//return;
		}

		std::string const body = "Hello at " + header->path;

		auto const try_send = [&yield, &make_sender](std::string const &data)
		{
			auto sender = make_sender(Si::incoming_bytes(data.data(), data.data() + data.size()));
			auto error = yield.get_one(sender);
			assert(error);
			return !*error;
		};

		{
			Si::http::response_header response;
			response.http_version = "HTTP/1.0";
			response.status_text = "OK";
			response.status = 200;
			response.arguments["Content-Length"] = boost::lexical_cast<std::string>(body.size());
			response.arguments["Connection"] = "close";

			std::string response_header;
			auto header_sink = Si::make_container_sink(response_header);
			Si::http::write_header(header_sink, response);

			if (!try_send(response_header))
			{
				return;
			}
		}

		if (!try_send(body))
		{
			return;
		}

		shutdown();

		while (Si::get(receive_bytes))
		{
		}
	}

	//TODO: use unique_observable
	using session_handle = Si::shared_observable<Si::nothing>;
}

int main()
{
	boost::asio::io_service io;
	boost::asio::ip::tcp::acceptor acceptor(io, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), 8080));
	Si::tcp_acceptor clients(acceptor);

	file_repository files;

	auto accept_all = Si::make_coroutine<session_handle>([&clients, &files](Si::yield_context<session_handle> &yield)
	{
		for (;;)
		{
			auto accepted = yield.get_one(clients);
			if (!accepted)
			{
				return;
			}
			Si::visit<void>(
				*accepted,
				[&yield, &files](std::shared_ptr<boost::asio::ip::tcp::socket> socket)
				{
					auto prepare_socket = [socket, &files](Si::yield_context<Si::nothing> &yield)
					{
						std::array<char, 1024> receive_buffer;
						Si::socket_observable received(*socket, boost::make_iterator_range(receive_buffer.data(), receive_buffer.data() + receive_buffer.size()));
						auto make_sender = [socket](Si::incoming_bytes sent)
						{
							return Si::sending_observable(*socket, to_range(sent));
						};
						auto shutdown = [socket]()
						{
							socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
						};
						serve_client(yield, received, make_sender, shutdown, files);
					};
					yield(Si::erase_shared(Si::make_coroutine<Si::nothing>(prepare_socket)));
				},
				[](boost::system::error_code)
				{
					throw std::logic_error("to do");
				}
			);
		}
	});
	auto all_sessions_finished = Si::flatten<boost::interprocess::null_mutex>(std::move(accept_all));
	auto done = Si::make_total_consumer(std::move(all_sessions_finished));
	done.start();
	io.run();
}
<commit_msg>list files recursively<commit_after>#include <silicium/tcp_acceptor.hpp>
#include <silicium/coroutine.hpp>
#include <silicium/total_consumer.hpp>
#include <silicium/flatten.hpp>
#include <silicium/socket_observable.hpp>
#include <silicium/sending_observable.hpp>
#include <silicium/received_from_socket_source.hpp>
#include <silicium/observable_source.hpp>
#include <silicium/for_each.hpp>
#include <silicium/optional.hpp>
#include <silicium/http/http.hpp>
#include <silicium/thread.hpp>
#include <boost/interprocess/sync/null_mutex.hpp>
#include <boost/container/string.hpp>
#include <boost/unordered_map.hpp>
#include <boost/filesystem/operations.hpp>

namespace
{
	using response_part = Si::incoming_bytes;

	boost::iterator_range<char const *> to_range(response_part part)
	{
		return boost::make_iterator_range(part.begin, part.end);
	}

	using byte = boost::uint8_t;
	using digest = boost::container::basic_string<byte>;

	struct content_request
	{
		digest requested_file;
	};

	Si::optional<unsigned char> decode_ascii_hex_digit(char digit)
	{
		switch (digit)
		{
		case '0': return 0;
		case '1': return 1;
		case '2': return 2;
		case '3': return 3;
		case '4': return 4;
		case '5': return 5;
		case '6': return 6;
		case '7': return 7;
		case '8': return 8;
		case '9': return 9;
		case 'a': case 'A': return 10;
		case 'b': case 'B': return 11;
		case 'c': case 'C': return 12;
		case 'd': case 'D': return 13;
		case 'e': case 'E': return 14;
		case 'f': case 'F': return 15;
		default:
			return Si::none;
		}
	}

	template <class InputIterator, class OutputIterator>
	std::pair<InputIterator, OutputIterator> decode_ascii_hex_bytes(InputIterator begin, InputIterator end, OutputIterator bytes)
	{
		for (;;)
		{
			if (begin == end)
			{
				break;
			}
			char const first_char = *begin;
			Si::optional<unsigned char> const first = decode_ascii_hex_digit(first_char);
			if (!first)
			{
				break;
			}
			auto const next = begin + 1;
			if (next == end)
			{
				break;
			}
			char const second_char = *next;
			Si::optional<unsigned char> const second = decode_ascii_hex_digit(second_char);
			if (!second)
			{
				break;
			}
			begin = next + 1;
			unsigned char const digit = static_cast<unsigned char>((*first * 16) + *second);
			*bytes = digit;
			++bytes;
		}
		return std::make_pair(begin, bytes);
	}

	Si::optional<content_request> parse_request_path(std::string const &path)
	{
		if (path.empty())
		{
			return Si::none;
		}
		auto digest_begin = path.begin();
		if (*digest_begin == '/')
		{
			++digest_begin;
		}
		content_request request;
		auto const rest = decode_ascii_hex_bytes(digest_begin, path.end(), std::back_inserter(request.requested_file));
		if (rest.first != path.end())
		{
			return Si::none;
		}
		return std::move(request);
	}

	struct file_system_location
	{
		//unique_ptr for noexcept-movability
		std::unique_ptr<boost::filesystem::path> where;
	};

	using location = Si::fast_variant<file_system_location>;

	struct file_repository
	{
		boost::unordered_map<digest, location> available;

		location const *find_location(digest const &key) const
		{
			auto i = available.find(key);
			return (i == end(available)) ? nullptr : &i->second;
		}
	};

	template <class ReceiveObservable, class MakeSender, class Shutdown>
	void serve_client(
		Si::yield_context<Si::nothing> &yield,
		ReceiveObservable &receive,
		MakeSender const &make_sender,
		Shutdown const &shutdown,
		file_repository const &repository)
	{
		auto receive_sync = Si::make_observable_source(Si::ref(receive), yield);
		Si::received_from_socket_source receive_bytes(receive_sync);
		auto header = Si::http::parse_header(receive_bytes);
		if (!header)
		{
			return;
		}

		auto const request = parse_request_path(header->path);
		if (!request)
		{
			//TODO: 404 or sth
			return;
		}

		location const * const found_file = repository.find_location(request->requested_file);
		if (!found_file)
		{
			//TODO: 404
			//return;
		}

		std::string const body = "Hello at " + header->path;

		auto const try_send = [&yield, &make_sender](std::string const &data)
		{
			auto sender = make_sender(Si::incoming_bytes(data.data(), data.data() + data.size()));
			auto error = yield.get_one(sender);
			assert(error);
			return !*error;
		};

		{
			Si::http::response_header response;
			response.http_version = "HTTP/1.0";
			response.status_text = "OK";
			response.status = 200;
			response.arguments["Content-Length"] = boost::lexical_cast<std::string>(body.size());
			response.arguments["Connection"] = "close";

			std::string response_header;
			auto header_sink = Si::make_container_sink(response_header);
			Si::http::write_header(header_sink, response);

			if (!try_send(response_header))
			{
				return;
			}
		}

		if (!try_send(body))
		{
			return;
		}

		shutdown();

		while (Si::get(receive_bytes))
		{
		}
	}

	//TODO: use unique_observable
	using session_handle = Si::shared_observable<Si::nothing>;

	namespace detail
	{
		void list_files_recursively(Si::yield_context_2<boost::filesystem::path> &yield, boost::filesystem::path const &root)
		{
			for (boost::filesystem::directory_iterator i(root); i != boost::filesystem::directory_iterator(); ++i)
			{
				switch (i->status().type())
				{
				case boost::filesystem::file_type::regular_file:
					yield.push_result(i->path());
					break;

				case boost::filesystem::file_type::directory_file:
					list_files_recursively(yield, i->path());
					break;

				default:
					//ignore
					break;
				}
			}
		}
	}

	Si::unique_observable<boost::filesystem::path> list_files_recursively(boost::filesystem::path const &root)
	{
		return Si::erase_unique(Si::make_thread<boost::filesystem::path, Si::boost_threading>([root](Si::yield_context_2<boost::filesystem::path> &yield)
		{
			return detail::list_files_recursively(yield, root);
		}));
	}
}

int main()
{
	boost::asio::io_service io;
	boost::asio::ip::tcp::acceptor acceptor(io, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), 8080));
	Si::tcp_acceptor clients(acceptor);

	file_repository files;

	auto accept_all = Si::make_coroutine<session_handle>([&clients, &files](Si::yield_context<session_handle> &yield)
	{
		for (;;)
		{
			auto accepted = yield.get_one(clients);
			if (!accepted)
			{
				return;
			}
			Si::visit<void>(
				*accepted,
				[&yield, &files](std::shared_ptr<boost::asio::ip::tcp::socket> socket)
				{
					auto prepare_socket = [socket, &files](Si::yield_context<Si::nothing> &yield)
					{
						std::array<char, 1024> receive_buffer;
						Si::socket_observable received(*socket, boost::make_iterator_range(receive_buffer.data(), receive_buffer.data() + receive_buffer.size()));
						auto make_sender = [socket](Si::incoming_bytes sent)
						{
							return Si::sending_observable(*socket, to_range(sent));
						};
						auto shutdown = [socket]()
						{
							socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
						};
						serve_client(yield, received, make_sender, shutdown, files);
					};
					yield(Si::erase_shared(Si::make_coroutine<Si::nothing>(prepare_socket)));
				},
				[](boost::system::error_code)
				{
					throw std::logic_error("to do");
				}
			);
		}
	});
	auto all_sessions_finished = Si::flatten<boost::interprocess::null_mutex>(std::move(accept_all));
	auto done = Si::make_total_consumer(std::move(all_sessions_finished));
	done.start();

	auto listed = Si::for_each(list_files_recursively(boost::filesystem::current_path()), [](boost::filesystem::path const &file)
	{
		std::cerr << file << '\n';
	});
	listed.start();

	io.run();
}
<|endoftext|>


<commit_before>#include "stdafx.h"

#include "CrashDump.h"
#include <atltime.h>
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")

#include "../../Common/Helpers/zip.h"
#include "../../Common/Helpers/RapidHelper.hpp"

namespace GameServer
{
    namespace Fixes
    {
        using UnhandledExceptionFilterPtr_t = LONG(WINAPIV*)(::_EXCEPTION_POINTERS *);
        using UnhandledExceptionFilterClbk_t = LONG(WINAPIV*)(::_EXCEPTION_POINTERS *, UnhandledExceptionFilterPtr_t);

        UnhandledExceptionFilterPtr_t UnhandledExceptionFilter_next(nullptr);
        UnhandledExceptionFilterClbk_t UnhandledExceptionFilter_user(nullptr);

        inline fs::path GetPathByHandle(HMODULE hModule)
        {
            TCHAR szPath[MAX_PATH] = {};
            GetModuleFileName(hModule, szPath, _countof(szPath));
            return fs::path(szPath);
        }

        inline fs::path GetGameServerExePath()
        {
            return GetPathByHandle(nullptr);
        }

        EXTERN_C IMAGE_DOS_HEADER __ImageBase;
        inline fs::path GetDllPath()
        {
            return GetPathByHandle((HMODULE)&__ImageBase);
        }

        void UnhandledExceptionFilter_wrapper(::_EXCEPTION_POINTERS * pExceptionInfo)
        {
            UnhandledExceptionFilter_user(pExceptionInfo, UnhandledExceptionFilter_next);
        };

        int CCrashDump::m_nCrash = 0;
        bool CCrashDump::m_bFullDump = false;
        const fs::path CCrashDump::m_pathCrashFolder = L".\\YorozuyaGS\\CrashDump\\";

        CCrashDump::CCrashDump()
        {
            HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
            if (hKernel != nullptr)
            {
                m_pSystemUnhandledFilter = GetProcAddress(hKernel, "UnhandledExceptionFilter");

                auto& core = ATF::CATFCore::get_instance();
                core.reg_wrapper(
                    &CCrashDump::UnhandledExceptionFilter,
                    ATF::_hook_record{
                        (LPVOID)m_pSystemUnhandledFilter,
                        (LPVOID *)&UnhandledExceptionFilter_user,
                        (LPVOID *)&UnhandledExceptionFilter_next,
                        (LPVOID)ATF::cast_pointer_function(UnhandledExceptionFilter_wrapper),
                        (LPVOID)ATF::cast_pointer_function((void(*)())&CCrashDump::UnhandledExceptionFilter)
                    });
            }
        }

        void CCrashDump::load()
        {
            enable_hook(&ATF::WheatyExceptionReport::GenerateExceptionReport, &CCrashDump::GenerateExceptionReport);
            enable_hook(&CCrashDump::UnhandledExceptionFilter, &CCrashDump::UnhandledExceptionFilter);

            fs::create_directories(m_pathCrashFolder);
        }

        void CCrashDump::unload()
        {
        }

        Yorozuya::Module::ModuleName_t CCrashDump::get_name()
        {
            static const Yorozuya::Module::ModuleName_t name = "system.crash_dump";
            return name;
        }

        void CCrashDump::configure(
            const rapidjson::Value & nodeConfig)
        {
            m_bFullDump = RapidHelper::GetValueOrDefault(nodeConfig, "full_dump", true);
        }

        ::std::wstring CCrashDump::BuildFileNameDump()
        {
            ::ATL::CTime tmCurrentTime(::ATL::CTime::GetCurrentTime());

            ::std::wstring wsRet(L"Dump " + ::std::to_wstring(m_nCrash++));

            return wsRet + tmCurrentTime.Format(L". %d.%m.%Y %H-%M-%S.dmp").GetString();
        }

        void WINAPIV CCrashDump::GenerateExceptionReport(
            ::_EXCEPTION_POINTERS* pExceptionInfo,
            ATF::Info::WheatyExceptionReportGenerateExceptionReport10_ptr next)
        {
            next((ATF::_EXCEPTION_POINTERS*)pExceptionInfo);

            fs::path pathFileDump(m_pathCrashFolder / BuildFileNameDump());

            HANDLE hFile = CreateFileW(
                pathFileDump.generic_wstring().c_str(),
                GENERIC_WRITE,
                0,
                nullptr,
                CREATE_ALWAYS,
                FILE_ATTRIBUTE_NORMAL,
                nullptr);

            if (hFile == INVALID_HANDLE_VALUE)
                return;

            MINIDUMP_EXCEPTION_INFORMATION eInfo;
            eInfo.ThreadId = GetCurrentThreadId();
            eInfo.ExceptionPointers = pExceptionInfo;
            eInfo.ClientPointers = FALSE;

            int type;
            if (CCrashDump::m_bFullDump)
            {
                type = MiniDumpWithFullMemory;
                type |= MiniDumpWithFullMemoryInfo;
                type |= MiniDumpWithHandleData;
                type |= MiniDumpWithUnloadedModules;
                type |= MiniDumpWithThreadInfo;
            }
            else
            {
                type = MiniDumpNormal;
                type |= MiniDumpWithDataSegs;
                type |= MiniDumpFilterModulePaths;
            }

            BOOL bWriteDump = MiniDumpWriteDump(
                GetCurrentProcess(),
                GetCurrentProcessId(),
                hFile,
                static_cast<_MINIDUMP_TYPE>(type),
                &eInfo,
                nullptr,
                nullptr);

            CloseHandle(hFile);

            if (bWriteDump != TRUE)
                return;

            ::std::vector<fs::path> vecRequiredFiles {
                pathFileDump,
                GetGameServerExePath(),
                GetDllPath(),
                GetDllPath().replace_extension(L"pdb")
            };

            auto pathZip = fs::path(pathFileDump).replace_extension(L"zip");

            do
            {
                HZIP hZip = CreateZip(pathZip.generic_wstring().c_str(), 0);
                if (hZip == nullptr)
                    break;

                size_t count = 0;
                ZRESULT hResult = ZR_OK;
                for (auto& file : vecRequiredFiles)
                {
                    hResult = ZipAdd(
                        hZip, file.filename().c_str(),
                        file.generic_wstring().c_str());

                    if (hResult == ZR_OK)
                    {
                        ++count;
                    }
                }

                CloseZip(hZip);

                if (count != vecRequiredFiles.size())
                    break;

                fs::remove(pathFileDump);
            } while (false);
        }

        LONG WINAPI CCrashDump::UnhandledExceptionFilter(::_EXCEPTION_POINTERS * ExceptionInfo)
        {
            UNREFERENCED_PARAMETER(ExceptionInfo);
            return EXCEPTION_CONTINUE_SEARCH;
        }
    }
}<commit_msg>Removed archiving crash dump<commit_after>#include "stdafx.h"

#include "CrashDump.h"
#include <atltime.h>
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")

#include "../../Common/Helpers/RapidHelper.hpp"

namespace GameServer
{
    namespace Fixes
    {
        using UnhandledExceptionFilterPtr_t = LONG(WINAPIV*)(::_EXCEPTION_POINTERS *);
        using UnhandledExceptionFilterClbk_t = LONG(WINAPIV*)(::_EXCEPTION_POINTERS *, UnhandledExceptionFilterPtr_t);

        UnhandledExceptionFilterPtr_t UnhandledExceptionFilter_next(nullptr);
        UnhandledExceptionFilterClbk_t UnhandledExceptionFilter_user(nullptr);

        inline fs::path GetPathByHandle(HMODULE hModule)
        {
            TCHAR szPath[MAX_PATH] = {};
            GetModuleFileName(hModule, szPath, _countof(szPath));
            return fs::path(szPath);
        }

        inline fs::path GetGameServerExePath()
        {
            return GetPathByHandle(nullptr);
        }

        EXTERN_C IMAGE_DOS_HEADER __ImageBase;
        inline fs::path GetDllPath()
        {
            return GetPathByHandle((HMODULE)&__ImageBase);
        }

        void UnhandledExceptionFilter_wrapper(::_EXCEPTION_POINTERS * pExceptionInfo)
        {
            UnhandledExceptionFilter_user(pExceptionInfo, UnhandledExceptionFilter_next);
        };

        int CCrashDump::m_nCrash = 0;
        bool CCrashDump::m_bFullDump = false;
        const fs::path CCrashDump::m_pathCrashFolder = L".\\YorozuyaGS\\CrashDump\\";

        CCrashDump::CCrashDump()
        {
            HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
            if (hKernel != nullptr)
            {
                m_pSystemUnhandledFilter = GetProcAddress(hKernel, "UnhandledExceptionFilter");

                auto& core = ATF::CATFCore::get_instance();
                core.reg_wrapper(
                    &CCrashDump::UnhandledExceptionFilter,
                    ATF::_hook_record{
                        (LPVOID)m_pSystemUnhandledFilter,
                        (LPVOID *)&UnhandledExceptionFilter_user,
                        (LPVOID *)&UnhandledExceptionFilter_next,
                        (LPVOID)ATF::cast_pointer_function(UnhandledExceptionFilter_wrapper),
                        (LPVOID)ATF::cast_pointer_function((void(*)())&CCrashDump::UnhandledExceptionFilter)
                    });
            }
        }

        void CCrashDump::load()
        {
            enable_hook(&ATF::WheatyExceptionReport::GenerateExceptionReport, &CCrashDump::GenerateExceptionReport);
            enable_hook(&CCrashDump::UnhandledExceptionFilter, &CCrashDump::UnhandledExceptionFilter);

            fs::create_directories(m_pathCrashFolder);
        }

        void CCrashDump::unload()
        {
        }

        Yorozuya::Module::ModuleName_t CCrashDump::get_name()
        {
            static const Yorozuya::Module::ModuleName_t name = "system.crash_dump";
            return name;
        }

        void CCrashDump::configure(
            const rapidjson::Value & nodeConfig)
        {
            m_bFullDump = RapidHelper::GetValueOrDefault(nodeConfig, "full_dump", true);
        }

        ::std::wstring CCrashDump::BuildFileNameDump()
        {
            ::ATL::CTime tmCurrentTime(::ATL::CTime::GetCurrentTime());

            ::std::wstring wsRet(L"Dump " + ::std::to_wstring(m_nCrash++));

            return wsRet + tmCurrentTime.Format(L". %d.%m.%Y %H-%M-%S.dmp").GetString();
        }

        void WINAPIV CCrashDump::GenerateExceptionReport(
            ::_EXCEPTION_POINTERS* pExceptionInfo,
            ATF::Info::WheatyExceptionReportGenerateExceptionReport10_ptr next)
        {
            next((ATF::_EXCEPTION_POINTERS*)pExceptionInfo);

            fs::path pathFileDump(m_pathCrashFolder / BuildFileNameDump());

            HANDLE hFile = CreateFileW(
                pathFileDump.generic_wstring().c_str(),
                GENERIC_WRITE,
                0,
                nullptr,
                CREATE_ALWAYS,
                FILE_ATTRIBUTE_NORMAL,
                nullptr);

            if (hFile == INVALID_HANDLE_VALUE)
                return;

            MINIDUMP_EXCEPTION_INFORMATION eInfo;
            eInfo.ThreadId = GetCurrentThreadId();
            eInfo.ExceptionPointers = pExceptionInfo;
            eInfo.ClientPointers = FALSE;

            int type;
            if (CCrashDump::m_bFullDump)
            {
                type = MiniDumpWithFullMemory;
                type |= MiniDumpWithFullMemoryInfo;
                type |= MiniDumpWithHandleData;
                type |= MiniDumpWithUnloadedModules;
                type |= MiniDumpWithThreadInfo;
            }
            else
            {
                type = MiniDumpNormal;
                type |= MiniDumpWithDataSegs;
                type |= MiniDumpFilterModulePaths;
            }

            BOOL bWriteDump = MiniDumpWriteDump(
                GetCurrentProcess(),
                GetCurrentProcessId(),
                hFile,
                static_cast<_MINIDUMP_TYPE>(type),
                &eInfo,
                nullptr,
                nullptr);

            CloseHandle(hFile);

            if (bWriteDump != TRUE)
                return;
        }

        LONG WINAPI CCrashDump::UnhandledExceptionFilter(::_EXCEPTION_POINTERS * ExceptionInfo)
        {
            UNREFERENCED_PARAMETER(ExceptionInfo);
            return EXCEPTION_CONTINUE_SEARCH;
        }
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/autofill/autofill_download.h"

#include <algorithm>
#include <ostream>
#include <vector>

#include "base/logging.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/string_util.h"
#include "chrome/browser/autofill/autofill_metrics.h"
#include "chrome/browser/autofill/autofill_xml_parser.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "content/public/common/url_fetcher.h"
#include "googleurl/src/gurl.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "third_party/libjingle/source/talk/xmllite/xmlparser.h"

namespace {
const char kAutofillQueryServerRequestUrl[] =
    "https://clients1.google.com/tbproxy/af/query?client=";
const char kAutofillUploadServerRequestUrl[] =
    "https://clients1.google.com/tbproxy/af/upload?client=";
const char kAutofillQueryServerNameStartInHeader[] = "GFE/";

#if defined(GOOGLE_CHROME_BUILD)
const char kClientName[] = "Google Chrome";
#else
const char kClientName[] = "Chromium";
#endif  // defined(GOOGLE_CHROME_BUILD)

const size_t kMaxFormCacheSize = 16;
};

struct AutofillDownloadManager::FormRequestData {
  std::vector<std::string> form_signatures;
  AutofillRequestType request_type;
};

AutofillDownloadManager::AutofillDownloadManager(Profile* profile,
                                                 Observer* observer)
    : profile_(profile),
      observer_(observer),
      max_form_cache_size_(kMaxFormCacheSize),
      next_query_request_(base::Time::Now()),
      next_upload_request_(base::Time::Now()),
      positive_upload_rate_(0),
      negative_upload_rate_(0),
      fetcher_id_for_unittest_(0) {
  DCHECK(observer_);
  PrefService* preferences = profile_->GetPrefs();
  positive_upload_rate_ =
      preferences->GetDouble(prefs::kAutofillPositiveUploadRate);
  negative_upload_rate_ =
      preferences->GetDouble(prefs::kAutofillNegativeUploadRate);
}

AutofillDownloadManager::~AutofillDownloadManager() {
  STLDeleteContainerPairFirstPointers(url_fetchers_.begin(),
                                      url_fetchers_.end());
}

bool AutofillDownloadManager::StartQueryRequest(
    const std::vector<FormStructure*>& forms,
    const AutofillMetrics& metric_logger) {
  if (next_query_request_ > base::Time::Now()) {
    // We are in back-off mode: do not do the request.
    return false;
  }
  std::string form_xml;
  FormRequestData request_data;
  if (!FormStructure::EncodeQueryRequest(forms, &request_data.form_signatures,
                                         &form_xml)) {
    return false;
  }

  request_data.request_type = AutofillDownloadManager::REQUEST_QUERY;
  metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_SENT);

  std::string query_data;
  if (CheckCacheForQueryRequest(request_data.form_signatures, &query_data)) {
    DVLOG(1) << "AutofillDownloadManager: query request has been retrieved from"
             << "the cache";
    observer_->OnLoadedServerPredictions(query_data);
    return true;
  }

  return StartRequest(form_xml, request_data);
}

bool AutofillDownloadManager::StartUploadRequest(
    const FormStructure& form,
    bool form_was_autofilled,
    const FieldTypeSet& available_field_types) {
  if (next_upload_request_ > base::Time::Now()) {
    // We are in back-off mode: do not do the request.
    DVLOG(1) << "AutofillDownloadManager: Upload request is throttled.";
    return false;
  }

  // Flip a coin to see if we should upload this form.
  double upload_rate = form_was_autofilled ? GetPositiveUploadRate() :
                                             GetNegativeUploadRate();
  if (form.upload_required() == UPLOAD_NOT_REQUIRED ||
      (form.upload_required() == USE_UPLOAD_RATES &&
       base::RandDouble() > upload_rate)) {
    DVLOG(1) << "AutofillDownloadManager: Upload request is ignored.";
    // If we ever need notification that upload was skipped, add it here.
    return false;
  }

  std::string form_xml;
  if (!form.EncodeUploadRequest(available_field_types, form_was_autofilled,
                                &form_xml))
    return false;

  FormRequestData request_data;
  request_data.form_signatures.push_back(form.FormSignature());
  request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD;

  return StartRequest(form_xml, request_data);
}

double AutofillDownloadManager::GetPositiveUploadRate() const {
  return positive_upload_rate_;
}

double AutofillDownloadManager::GetNegativeUploadRate() const {
  return negative_upload_rate_;
}

void AutofillDownloadManager::SetPositiveUploadRate(double rate) {
  if (rate == positive_upload_rate_)
    return;
  positive_upload_rate_ = rate;
  DCHECK_GE(rate, 0.0);
  DCHECK_LE(rate, 1.0);
  PrefService* preferences = profile_->GetPrefs();
  preferences->SetDouble(prefs::kAutofillPositiveUploadRate, rate);
}

void AutofillDownloadManager::SetNegativeUploadRate(double rate) {
  if (rate == negative_upload_rate_)
    return;
  negative_upload_rate_ = rate;
  DCHECK_GE(rate, 0.0);
  DCHECK_LE(rate, 1.0);
  PrefService* preferences = profile_->GetPrefs();
  preferences->SetDouble(prefs::kAutofillNegativeUploadRate, rate);
}

bool AutofillDownloadManager::StartRequest(
    const std::string& form_xml,
    const FormRequestData& request_data) {
  net::URLRequestContextGetter* request_context = profile_->GetRequestContext();
  DCHECK(request_context);
  std::string request_url;
  if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY)
    request_url = kAutofillQueryServerRequestUrl;
  else
    request_url = kAutofillUploadServerRequestUrl;
  request_url += kClientName;

  // Id is ignored for regular chrome, in unit test id's for fake fetcher
  // factory will be 0, 1, 2, ...
  content::URLFetcher* fetcher = content::URLFetcher::Create(
      fetcher_id_for_unittest_++, GURL(request_url), content::URLFetcher::POST,
      this);
  url_fetchers_[fetcher] = request_data;
  fetcher->SetAutomaticallyRetryOn5xx(false);
  fetcher->SetRequestContext(request_context);
  fetcher->SetUploadData("text/plain", form_xml);
  fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
  fetcher->Start();
  return true;
}

void AutofillDownloadManager::CacheQueryRequest(
    const std::vector<std::string>& forms_in_query,
    const std::string& query_data) {
  std::string signature = GetCombinedSignature(forms_in_query);
  for (QueryRequestCache::iterator it = cached_forms_.begin();
       it != cached_forms_.end(); ++it) {
    if (it->first == signature) {
      // We hit the cache, move to the first position and return.
      std::pair<std::string, std::string> data = *it;
      cached_forms_.erase(it);
      cached_forms_.push_front(data);
      return;
    }
  }
  std::pair<std::string, std::string> data;
  data.first = signature;
  data.second = query_data;
  cached_forms_.push_front(data);
  while (cached_forms_.size() > max_form_cache_size_)
    cached_forms_.pop_back();
}

bool AutofillDownloadManager::CheckCacheForQueryRequest(
    const std::vector<std::string>& forms_in_query,
    std::string* query_data) const {
  std::string signature = GetCombinedSignature(forms_in_query);
  for (QueryRequestCache::const_iterator it = cached_forms_.begin();
       it != cached_forms_.end(); ++it) {
    if (it->first == signature) {
      // We hit the cache, fill the data and return.
      *query_data = it->second;
      return true;
    }
  }
  return false;
}

std::string AutofillDownloadManager::GetCombinedSignature(
    const std::vector<std::string>& forms_in_query) const {
  size_t total_size = forms_in_query.size();
  for (size_t i = 0; i < forms_in_query.size(); ++i)
    total_size += forms_in_query[i].length();
  std::string signature;

  signature.reserve(total_size);

  for (size_t i = 0; i < forms_in_query.size(); ++i) {
    if (i)
      signature.append(",");
    signature.append(forms_in_query[i]);
  }
  return signature;
}

void AutofillDownloadManager::OnURLFetchComplete(
    const content::URLFetcher* source) {
  std::map<content::URLFetcher *, FormRequestData>::iterator it =
      url_fetchers_.find(const_cast<content::URLFetcher*>(source));
  if (it == url_fetchers_.end()) {
    // Looks like crash on Mac is possibly caused with callback entering here
    // with unknown fetcher when network is refreshed.
    return;
  }
  std::string type_of_request(
      it->second.request_type == AutofillDownloadManager::REQUEST_QUERY ?
          "query" : "upload");
  const int kHttpResponseOk = 200;
  const int kHttpInternalServerError = 500;
  const int kHttpBadGateway = 502;
  const int kHttpServiceUnavailable = 503;

  CHECK(it->second.form_signatures.size());
  if (source->GetResponseCode() != kHttpResponseOk) {
    bool back_off = false;
    std::string server_header;
    switch (source->GetResponseCode()) {
      case kHttpBadGateway:
        if (!source->GetResponseHeaders()->EnumerateHeader(NULL, "server",
                                                           &server_header) ||
            StartsWithASCII(server_header.c_str(),
                            kAutofillQueryServerNameStartInHeader,
                            false) != 0)
          break;
        // Bad gateway was received from Autofill servers. Fall through to back
        // off.
      case kHttpInternalServerError:
      case kHttpServiceUnavailable:
        back_off = true;
        break;
    }

    if (back_off) {
      base::Time back_off_time(base::Time::Now() + source->GetBackoffDelay());
      if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) {
        next_query_request_ = back_off_time;
      } else {
        next_upload_request_ = back_off_time;
      }
    }

    DVLOG(1) << "AutofillDownloadManager: " << type_of_request
             << " request has failed with response "
             << source->GetResponseCode();
    observer_->OnServerRequestError(it->second.form_signatures[0],
                                    it->second.request_type,
                                    source->GetResponseCode());
  } else {
    DVLOG(1) << "AutofillDownloadManager: " << type_of_request
             << " request has succeeded";
    std::string response_body;
    source->GetResponseAsString(&response_body);
    if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) {
      CacheQueryRequest(it->second.form_signatures, response_body);
      observer_->OnLoadedServerPredictions(response_body);
    } else {
      double new_positive_upload_rate = 0;
      double new_negative_upload_rate = 0;
      AutofillUploadXmlParser parse_handler(&new_positive_upload_rate,
                                            &new_negative_upload_rate);
      buzz::XmlParser parser(&parse_handler);
      parser.Parse(response_body.data(), response_body.length(), true);
      if (parse_handler.succeeded()) {
        SetPositiveUploadRate(new_positive_upload_rate);
        SetNegativeUploadRate(new_negative_upload_rate);
      }

      observer_->OnUploadedPossibleFieldTypes();
    }
  }
  delete it->first;
  url_fetchers_.erase(it);
}
<commit_msg>Added net::LOAD_DO_NOT_SEND_COOKIES to autofil_download to fix: 118932:  URLFetcher::Create calls in chrome/browser/autofill/autofill_download.cc<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/autofill/autofill_download.h"

#include <algorithm>
#include <ostream>
#include <vector>

#include "base/logging.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/string_util.h"
#include "chrome/browser/autofill/autofill_metrics.h"
#include "chrome/browser/autofill/autofill_xml_parser.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "content/public/common/url_fetcher.h"
#include "googleurl/src/gurl.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "third_party/libjingle/source/talk/xmllite/xmlparser.h"

namespace {
const char kAutofillQueryServerRequestUrl[] =
    "https://clients1.google.com/tbproxy/af/query?client=";
const char kAutofillUploadServerRequestUrl[] =
    "https://clients1.google.com/tbproxy/af/upload?client=";
const char kAutofillQueryServerNameStartInHeader[] = "GFE/";

#if defined(GOOGLE_CHROME_BUILD)
const char kClientName[] = "Google Chrome";
#else
const char kClientName[] = "Chromium";
#endif  // defined(GOOGLE_CHROME_BUILD)

const size_t kMaxFormCacheSize = 16;
};

struct AutofillDownloadManager::FormRequestData {
  std::vector<std::string> form_signatures;
  AutofillRequestType request_type;
};

AutofillDownloadManager::AutofillDownloadManager(Profile* profile,
                                                 Observer* observer)
    : profile_(profile),
      observer_(observer),
      max_form_cache_size_(kMaxFormCacheSize),
      next_query_request_(base::Time::Now()),
      next_upload_request_(base::Time::Now()),
      positive_upload_rate_(0),
      negative_upload_rate_(0),
      fetcher_id_for_unittest_(0) {
  DCHECK(observer_);
  PrefService* preferences = profile_->GetPrefs();
  positive_upload_rate_ =
      preferences->GetDouble(prefs::kAutofillPositiveUploadRate);
  negative_upload_rate_ =
      preferences->GetDouble(prefs::kAutofillNegativeUploadRate);
}

AutofillDownloadManager::~AutofillDownloadManager() {
  STLDeleteContainerPairFirstPointers(url_fetchers_.begin(),
                                      url_fetchers_.end());
}

bool AutofillDownloadManager::StartQueryRequest(
    const std::vector<FormStructure*>& forms,
    const AutofillMetrics& metric_logger) {
  if (next_query_request_ > base::Time::Now()) {
    // We are in back-off mode: do not do the request.
    return false;
  }
  std::string form_xml;
  FormRequestData request_data;
  if (!FormStructure::EncodeQueryRequest(forms, &request_data.form_signatures,
                                         &form_xml)) {
    return false;
  }

  request_data.request_type = AutofillDownloadManager::REQUEST_QUERY;
  metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_SENT);

  std::string query_data;
  if (CheckCacheForQueryRequest(request_data.form_signatures, &query_data)) {
    DVLOG(1) << "AutofillDownloadManager: query request has been retrieved from"
             << "the cache";
    observer_->OnLoadedServerPredictions(query_data);
    return true;
  }

  return StartRequest(form_xml, request_data);
}

bool AutofillDownloadManager::StartUploadRequest(
    const FormStructure& form,
    bool form_was_autofilled,
    const FieldTypeSet& available_field_types) {
  if (next_upload_request_ > base::Time::Now()) {
    // We are in back-off mode: do not do the request.
    DVLOG(1) << "AutofillDownloadManager: Upload request is throttled.";
    return false;
  }

  // Flip a coin to see if we should upload this form.
  double upload_rate = form_was_autofilled ? GetPositiveUploadRate() :
                                             GetNegativeUploadRate();
  if (form.upload_required() == UPLOAD_NOT_REQUIRED ||
      (form.upload_required() == USE_UPLOAD_RATES &&
       base::RandDouble() > upload_rate)) {
    DVLOG(1) << "AutofillDownloadManager: Upload request is ignored.";
    // If we ever need notification that upload was skipped, add it here.
    return false;
  }

  std::string form_xml;
  if (!form.EncodeUploadRequest(available_field_types, form_was_autofilled,
                                &form_xml))
    return false;

  FormRequestData request_data;
  request_data.form_signatures.push_back(form.FormSignature());
  request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD;

  return StartRequest(form_xml, request_data);
}

double AutofillDownloadManager::GetPositiveUploadRate() const {
  return positive_upload_rate_;
}

double AutofillDownloadManager::GetNegativeUploadRate() const {
  return negative_upload_rate_;
}

void AutofillDownloadManager::SetPositiveUploadRate(double rate) {
  if (rate == positive_upload_rate_)
    return;
  positive_upload_rate_ = rate;
  DCHECK_GE(rate, 0.0);
  DCHECK_LE(rate, 1.0);
  PrefService* preferences = profile_->GetPrefs();
  preferences->SetDouble(prefs::kAutofillPositiveUploadRate, rate);
}

void AutofillDownloadManager::SetNegativeUploadRate(double rate) {
  if (rate == negative_upload_rate_)
    return;
  negative_upload_rate_ = rate;
  DCHECK_GE(rate, 0.0);
  DCHECK_LE(rate, 1.0);
  PrefService* preferences = profile_->GetPrefs();
  preferences->SetDouble(prefs::kAutofillNegativeUploadRate, rate);
}

bool AutofillDownloadManager::StartRequest(
    const std::string& form_xml,
    const FormRequestData& request_data) {
  net::URLRequestContextGetter* request_context = profile_->GetRequestContext();
  DCHECK(request_context);
  std::string request_url;
  if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY)
    request_url = kAutofillQueryServerRequestUrl;
  else
    request_url = kAutofillUploadServerRequestUrl;
  request_url += kClientName;

  // Id is ignored for regular chrome, in unit test id's for fake fetcher
  // factory will be 0, 1, 2, ...
  content::URLFetcher* fetcher = content::URLFetcher::Create(
      fetcher_id_for_unittest_++, GURL(request_url), content::URLFetcher::POST,
      this);
  url_fetchers_[fetcher] = request_data;
  fetcher->SetAutomaticallyRetryOn5xx(false);
  fetcher->SetRequestContext(request_context);
  fetcher->SetUploadData("text/plain", form_xml);
  fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
                        net::LOAD_DO_NOT_SEND_COOKIES);
  fetcher->Start();
  return true;
}

void AutofillDownloadManager::CacheQueryRequest(
    const std::vector<std::string>& forms_in_query,
    const std::string& query_data) {
  std::string signature = GetCombinedSignature(forms_in_query);
  for (QueryRequestCache::iterator it = cached_forms_.begin();
       it != cached_forms_.end(); ++it) {
    if (it->first == signature) {
      // We hit the cache, move to the first position and return.
      std::pair<std::string, std::string> data = *it;
      cached_forms_.erase(it);
      cached_forms_.push_front(data);
      return;
    }
  }
  std::pair<std::string, std::string> data;
  data.first = signature;
  data.second = query_data;
  cached_forms_.push_front(data);
  while (cached_forms_.size() > max_form_cache_size_)
    cached_forms_.pop_back();
}

bool AutofillDownloadManager::CheckCacheForQueryRequest(
    const std::vector<std::string>& forms_in_query,
    std::string* query_data) const {
  std::string signature = GetCombinedSignature(forms_in_query);
  for (QueryRequestCache::const_iterator it = cached_forms_.begin();
       it != cached_forms_.end(); ++it) {
    if (it->first == signature) {
      // We hit the cache, fill the data and return.
      *query_data = it->second;
      return true;
    }
  }
  return false;
}

std::string AutofillDownloadManager::GetCombinedSignature(
    const std::vector<std::string>& forms_in_query) const {
  size_t total_size = forms_in_query.size();
  for (size_t i = 0; i < forms_in_query.size(); ++i)
    total_size += forms_in_query[i].length();
  std::string signature;

  signature.reserve(total_size);

  for (size_t i = 0; i < forms_in_query.size(); ++i) {
    if (i)
      signature.append(",");
    signature.append(forms_in_query[i]);
  }
  return signature;
}

void AutofillDownloadManager::OnURLFetchComplete(
    const content::URLFetcher* source) {
  std::map<content::URLFetcher *, FormRequestData>::iterator it =
      url_fetchers_.find(const_cast<content::URLFetcher*>(source));
  if (it == url_fetchers_.end()) {
    // Looks like crash on Mac is possibly caused with callback entering here
    // with unknown fetcher when network is refreshed.
    return;
  }
  std::string type_of_request(
      it->second.request_type == AutofillDownloadManager::REQUEST_QUERY ?
          "query" : "upload");
  const int kHttpResponseOk = 200;
  const int kHttpInternalServerError = 500;
  const int kHttpBadGateway = 502;
  const int kHttpServiceUnavailable = 503;

  CHECK(it->second.form_signatures.size());
  if (source->GetResponseCode() != kHttpResponseOk) {
    bool back_off = false;
    std::string server_header;
    switch (source->GetResponseCode()) {
      case kHttpBadGateway:
        if (!source->GetResponseHeaders()->EnumerateHeader(NULL, "server",
                                                           &server_header) ||
            StartsWithASCII(server_header.c_str(),
                            kAutofillQueryServerNameStartInHeader,
                            false) != 0)
          break;
        // Bad gateway was received from Autofill servers. Fall through to back
        // off.
      case kHttpInternalServerError:
      case kHttpServiceUnavailable:
        back_off = true;
        break;
    }

    if (back_off) {
      base::Time back_off_time(base::Time::Now() + source->GetBackoffDelay());
      if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) {
        next_query_request_ = back_off_time;
      } else {
        next_upload_request_ = back_off_time;
      }
    }

    DVLOG(1) << "AutofillDownloadManager: " << type_of_request
             << " request has failed with response "
             << source->GetResponseCode();
    observer_->OnServerRequestError(it->second.form_signatures[0],
                                    it->second.request_type,
                                    source->GetResponseCode());
  } else {
    DVLOG(1) << "AutofillDownloadManager: " << type_of_request
             << " request has succeeded";
    std::string response_body;
    source->GetResponseAsString(&response_body);
    if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) {
      CacheQueryRequest(it->second.form_signatures, response_body);
      observer_->OnLoadedServerPredictions(response_body);
    } else {
      double new_positive_upload_rate = 0;
      double new_negative_upload_rate = 0;
      AutofillUploadXmlParser parse_handler(&new_positive_upload_rate,
                                            &new_negative_upload_rate);
      buzz::XmlParser parser(&parse_handler);
      parser.Parse(response_body.data(), response_body.length(), true);
      if (parse_handler.succeeded()) {
        SetPositiveUploadRate(new_positive_upload_rate);
        SetNegativeUploadRate(new_negative_upload_rate);
      }

      observer_->OnUploadedPossibleFieldTypes();
    }
  }
  delete it->first;
  url_fetchers_.erase(it);
}
<|endoftext|>


<commit_before>// Time:  O(nlogn)
// Space: O(n)

class Solution {
public:
    class BSTreeNode {
    public:
        int val, count;
        BSTreeNode *left, *right;
        BSTreeNode(int val, int count) {
            this->val = val;
            this->count = count;
            this->left = this->right = nullptr;
        }
    };
    /**
     * @param A: An integer array
     * @return: Count the number of element before this element 'ai' is
     *          smaller than it and return count number array
     */
    vector<int> countOfSmallerNumberII(vector<int> &A) {
        vector<int> res;

        BSTreeNode *root = nullptr;

        // Insert into BST and get left count.
        for (int i = 0; i < A.size(); ++i) {
            int count = 0;
            BSTreeNode *node = new BSTreeNode(A[i], 0);
            root = insertNode(root, node);
            count = query(root, A[i]);
            res.emplace_back(count);
        }

        return res;
    }

    // Insert node into BST.
    BSTreeNode* insertNode(BSTreeNode* root, BSTreeNode* node) {
        if (root == nullptr) {
            return node;
        }
        BSTreeNode* curr = root;
        while (curr) {
            // Insert left if smaller.
            if (node->val < curr->val) {
                ++curr->count; // Increase the number of left children.
                if (curr->left != nullptr) {
                    curr = curr->left;
                } else {
                    curr->left = node;
                    break;
                }
            } else {  // Insert right if larger or equal.
                if (curr->right != nullptr) {
                    curr = curr->right;
                } else {
                    curr->right = node;
                    break;
                }
            }
        }
        return root;
    }

    // Query the smaller count of the value.
    int query(BSTreeNode* root, int val) {
        if (root == nullptr) {
            return 0;
        }
        int count = 0;
        BSTreeNode* curr = root;
        while (curr) {
            // Insert left.
            if (val < curr->val) {
                curr = curr->left;
            } else if (val > curr->val) {
                count += 1 + curr->count; // Count the number of the smaller nodes.
                curr = curr->right;
            } else {  // Equal.
                return count + curr->count;
            }
        }
        return 0;
    }
};
<commit_msg>Update count-of-smaller-number-before-itself.cpp<commit_after>// Time:  O(nlogn)
// Space: O(n)

// BIT solution. (281ms)
class Solution {
public:
   /**
     * @param A: An integer array
     * @return: Count the number of element before this element 'ai' is
     *          smaller than it and return count number array
     */
    vector<int> countOfSmallerNumberII(vector<int> &A) {
        vector<int> sorted_A(A), orderings(A.size());
        sort(sorted_A.begin(), sorted_A.end());
        for (int i = 0; i < A.size(); ++i) {
            orderings[i] =
                lower_bound(sorted_A.begin(), sorted_A.end(), A[i]) -
                sorted_A.begin();
        }
        vector<int> bit(A.size() + 1), ans(A.size());
        for (int i = 0; i < orderings.size(); ++i) {
            ans[i] = query(bit, orderings[i]);
            add(bit, orderings[i] + 1, 1);
        }
        return ans;
    }

private:
    void add(vector<int>& bit, int i, int val) {
        for (; i < bit.size(); i += lower_bit(i)) {
            bit[i] += val;
        }
    }

    int query(const vector<int>& bit, int i) {
        int sum = 0;
        for (; i > 0; i -= lower_bit(i)) {
            sum += bit[i];
        }
        return sum;
    }

    int lower_bit(int i) {
        return i & -i;
    }
};

// Time:  O(nlogn)
// Space: O(n)
// BST solution. (743ms)
class Solution2 {
public:
    class BSTreeNode {
    public:
        int val, count;
        BSTreeNode *left, *right;
        BSTreeNode(int val, int count) {
            this->val = val;
            this->count = count;
            this->left = this->right = nullptr;
        }
    };
    /**
     * @param A: An integer array
     * @return: Count the number of element before this element 'ai' is
     *          smaller than it and return count number array
     */
    vector<int> countOfSmallerNumberII(vector<int> &A) {
        vector<int> res;

        BSTreeNode *root = nullptr;

        // Insert into BST and get left count.
        for (int i = 0; i < A.size(); ++i) {
            int count = 0;
            BSTreeNode *node = new BSTreeNode(A[i], 0);
            root = insertNode(root, node);
            count = query(root, A[i]);
            res.emplace_back(count);
        }

        return res;
    }

    // Insert node into BST.
    BSTreeNode* insertNode(BSTreeNode* root, BSTreeNode* node) {
        if (root == nullptr) {
            return node;
        }
        BSTreeNode* curr = root;
        while (curr) {
            // Insert left if smaller.
            if (node->val < curr->val) {
                ++curr->count; // Increase the number of left children.
                if (curr->left != nullptr) {
                    curr = curr->left;
                } else {
                    curr->left = node;
                    break;
                }
            } else {  // Insert right if larger or equal.
                if (curr->right != nullptr) {
                    curr = curr->right;
                } else {
                    curr->right = node;
                    break;
                }
            }
        }
        return root;
    }

    // Query the smaller count of the value.
    int query(BSTreeNode* root, int val) {
        if (root == nullptr) {
            return 0;
        }
        int count = 0;
        BSTreeNode* curr = root;
        while (curr) {
            // Insert left.
            if (val < curr->val) {
                curr = curr->left;
            } else if (val > curr->val) {
                count += 1 + curr->count; // Count the number of the smaller nodes.
                curr = curr->right;
            } else {  // Equal.
                return count + curr->count;
            }
        }
        return 0;
    }
};
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/surface/transport_dib.h"
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/ref_counted_memory.h"
#include "base/stringprintf.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/renderer/render_widget_browsertest.h"
#include "gfx/codec/jpeg_codec.h"
#include "gfx/size.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"

const int RenderWidgetTest::kNumBytesPerPixel = 4;
const int RenderWidgetTest::kLargeWidth = 1024;
const int RenderWidgetTest::kLargeHeight = 768;
const int RenderWidgetTest::kSmallWidth = 600;
const int RenderWidgetTest::kSmallHeight = 450;
const int RenderWidgetTest::kTextPositionX = 800;
const int RenderWidgetTest::kTextPositionY = 600;
const int RenderWidgetTest::kSequenceNum = 1;
const uint32 RenderWidgetTest::kRedARGB = 0xFFFF0000;

RenderWidgetTest::RenderWidgetTest() {}

void RenderWidgetTest::ResizeAndPaint(const gfx::Size& page_size,
                                      const gfx::Size& desired_size,
                                      SkBitmap* snapshot) {
  ASSERT_TRUE(snapshot);
  scoped_ptr<TransportDIB> pixels(
      TransportDIB::Create(
          page_size.width() * page_size.height() * kNumBytesPerPixel,
          kSequenceNum));
  view_->OnMsgPaintAtSize(pixels->handle(), kSequenceNum, page_size,
                          desired_size);
  ProcessPendingMessages();
  const IPC::Message* msg = render_thread_.sink().GetUniqueMessageMatching(
      ViewHostMsg_PaintAtSize_ACK::ID);
  ASSERT_NE(static_cast<IPC::Message*>(NULL), msg);
  ViewHostMsg_PaintAtSize_ACK::Param params;
  ViewHostMsg_PaintAtSize_ACK::Read(msg, &params);
  render_thread_.sink().ClearMessages();
  EXPECT_EQ(kSequenceNum, params.a);
  gfx::Size size = params.b;
  EXPECT_EQ(desired_size, size);

  SkBitmap tmp_bitmap;
  tmp_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
                       size.width(), size.height());
  tmp_bitmap.setPixels(pixels->memory());
  // Copy the pixels from the TransportDIB object to the given snapshot.
  ASSERT_TRUE(tmp_bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config));
}

void RenderWidgetTest::TestResizeAndPaint() {
  // Hello World message is only visible if the view size is at least
  // kTextPositionX x kTextPositionY
  LoadHTML(StringPrintf(
      "
Hello World
",
      kTextPositionY, kTextPositionX).c_str());
  WebKit::WebSize old_size = view_->webview()->size();

  SkBitmap bitmap;
  // If we re-size the view to something smaller than where the 'Hello World'
  // text is displayed we won't see any text in the snapshot.  Hence,
  // the snapshot should not contain any red.
  gfx::Size size(kSmallWidth, kSmallHeight);
  ResizeAndPaint(size, size, &bitmap);
  // Make sure that the view has been re-sized to its old size.
  EXPECT_EQ(old_size, view_->webview()->size());
  EXPECT_EQ(kSmallWidth, bitmap.width());
  EXPECT_EQ(kSmallHeight, bitmap.height());
  EXPECT_FALSE(ImageContainsColor(bitmap, kRedARGB));

  // Since we ask for the view to be re-sized to something larger than where the
  // 'Hello World' text is written the text should be visible in the snapshot.
  // Hence, the snapshot should contain some red.
  size.SetSize(kLargeWidth, kLargeHeight);
  ResizeAndPaint(size, size, &bitmap);
  EXPECT_EQ(old_size, view_->webview()->size());
  EXPECT_EQ(kLargeWidth, bitmap.width());
  EXPECT_EQ(kLargeHeight, bitmap.height());
  EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB));

  // Even if the desired size is smaller than where the text is located we
  // should still see the 'Hello World' message since the view size is
  // still large enough.
  ResizeAndPaint(size, gfx::Size(kSmallWidth, kSmallHeight), &bitmap);
  EXPECT_EQ(old_size, view_->webview()->size());
  EXPECT_EQ(kSmallWidth, bitmap.width());
  EXPECT_EQ(kSmallHeight, bitmap.height());
  EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB));
}

bool RenderWidgetTest::ImageContainsColor(const SkBitmap& bitmap,
                                          uint32 argb_color) {
  SkAutoLockPixels lock(bitmap);
  bool ready = bitmap.readyToDraw();
  EXPECT_TRUE(ready);
  if (!ready) {
    return false;
  }
  for (int x = 0; x < bitmap.width(); ++x) {
    for (int y = 0; y < bitmap.height(); ++y) {
      if (argb_color == *bitmap.getAddr32(x, y)) {
        return true;
      }
    }
  }
  return false;
}

void RenderWidgetTest::OutputBitmapToFile(const SkBitmap& bitmap,
                                          const FilePath& file_path) {
  scoped_refptr<RefCountedBytes> bitmap_data = new RefCountedBytes();
  SkAutoLockPixels lock(bitmap);
  ASSERT_TRUE(gfx::JPEGCodec::Encode(
      reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
      gfx::JPEGCodec::FORMAT_BGRA,
      bitmap.width(),
      bitmap.height(),
      static_cast<int>(bitmap.rowBytes()),
      90 /* quality */,
      &bitmap_data->data));
  ASSERT_LT(0, file_util::WriteFile(
      file_path,
      reinterpret_cast<const char*>(bitmap_data->front()),
      bitmap_data->size()));
}

TEST_F(RenderWidgetTest, OnMsgPaintAtSize) {
  TestResizeAndPaint();
}
<commit_msg>Mark failing test OnMsgPaintAtSize failing TBR=noelutz BUG=none TEST=none Review URL: http://codereview.chromium.org/3470011<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/surface/transport_dib.h"
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/ref_counted_memory.h"
#include "base/stringprintf.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/renderer/render_widget_browsertest.h"
#include "gfx/codec/jpeg_codec.h"
#include "gfx/size.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"

const int RenderWidgetTest::kNumBytesPerPixel = 4;
const int RenderWidgetTest::kLargeWidth = 1024;
const int RenderWidgetTest::kLargeHeight = 768;
const int RenderWidgetTest::kSmallWidth = 600;
const int RenderWidgetTest::kSmallHeight = 450;
const int RenderWidgetTest::kTextPositionX = 800;
const int RenderWidgetTest::kTextPositionY = 600;
const int RenderWidgetTest::kSequenceNum = 1;
const uint32 RenderWidgetTest::kRedARGB = 0xFFFF0000;

RenderWidgetTest::RenderWidgetTest() {}

void RenderWidgetTest::ResizeAndPaint(const gfx::Size& page_size,
                                      const gfx::Size& desired_size,
                                      SkBitmap* snapshot) {
  ASSERT_TRUE(snapshot);
  scoped_ptr<TransportDIB> pixels(
      TransportDIB::Create(
          page_size.width() * page_size.height() * kNumBytesPerPixel,
          kSequenceNum));
  view_->OnMsgPaintAtSize(pixels->handle(), kSequenceNum, page_size,
                          desired_size);
  ProcessPendingMessages();
  const IPC::Message* msg = render_thread_.sink().GetUniqueMessageMatching(
      ViewHostMsg_PaintAtSize_ACK::ID);
  ASSERT_NE(static_cast<IPC::Message*>(NULL), msg);
  ViewHostMsg_PaintAtSize_ACK::Param params;
  ViewHostMsg_PaintAtSize_ACK::Read(msg, &params);
  render_thread_.sink().ClearMessages();
  EXPECT_EQ(kSequenceNum, params.a);
  gfx::Size size = params.b;
  EXPECT_EQ(desired_size, size);

  SkBitmap tmp_bitmap;
  tmp_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
                       size.width(), size.height());
  tmp_bitmap.setPixels(pixels->memory());
  // Copy the pixels from the TransportDIB object to the given snapshot.
  ASSERT_TRUE(tmp_bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config));
}

void RenderWidgetTest::TestResizeAndPaint() {
  // Hello World message is only visible if the view size is at least
  // kTextPositionX x kTextPositionY
  LoadHTML(StringPrintf(
      "
Hello World
",
      kTextPositionY, kTextPositionX).c_str());
  WebKit::WebSize old_size = view_->webview()->size();

  SkBitmap bitmap;
  // If we re-size the view to something smaller than where the 'Hello World'
  // text is displayed we won't see any text in the snapshot.  Hence,
  // the snapshot should not contain any red.
  gfx::Size size(kSmallWidth, kSmallHeight);
  ResizeAndPaint(size, size, &bitmap);
  // Make sure that the view has been re-sized to its old size.
  EXPECT_EQ(old_size, view_->webview()->size());
  EXPECT_EQ(kSmallWidth, bitmap.width());
  EXPECT_EQ(kSmallHeight, bitmap.height());
  EXPECT_FALSE(ImageContainsColor(bitmap, kRedARGB));

  // Since we ask for the view to be re-sized to something larger than where the
  // 'Hello World' text is written the text should be visible in the snapshot.
  // Hence, the snapshot should contain some red.
  size.SetSize(kLargeWidth, kLargeHeight);
  ResizeAndPaint(size, size, &bitmap);
  EXPECT_EQ(old_size, view_->webview()->size());
  EXPECT_EQ(kLargeWidth, bitmap.width());
  EXPECT_EQ(kLargeHeight, bitmap.height());
  EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB));

  // Even if the desired size is smaller than where the text is located we
  // should still see the 'Hello World' message since the view size is
  // still large enough.
  ResizeAndPaint(size, gfx::Size(kSmallWidth, kSmallHeight), &bitmap);
  EXPECT_EQ(old_size, view_->webview()->size());
  EXPECT_EQ(kSmallWidth, bitmap.width());
  EXPECT_EQ(kSmallHeight, bitmap.height());
  EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB));
}

bool RenderWidgetTest::ImageContainsColor(const SkBitmap& bitmap,
                                          uint32 argb_color) {
  SkAutoLockPixels lock(bitmap);
  bool ready = bitmap.readyToDraw();
  EXPECT_TRUE(ready);
  if (!ready) {
    return false;
  }
  for (int x = 0; x < bitmap.width(); ++x) {
    for (int y = 0; y < bitmap.height(); ++y) {
      if (argb_color == *bitmap.getAddr32(x, y)) {
        return true;
      }
    }
  }
  return false;
}

void RenderWidgetTest::OutputBitmapToFile(const SkBitmap& bitmap,
                                          const FilePath& file_path) {
  scoped_refptr<RefCountedBytes> bitmap_data = new RefCountedBytes();
  SkAutoLockPixels lock(bitmap);
  ASSERT_TRUE(gfx::JPEGCodec::Encode(
      reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
      gfx::JPEGCodec::FORMAT_BGRA,
      bitmap.width(),
      bitmap.height(),
      static_cast<int>(bitmap.rowBytes()),
      90 /* quality */,
      &bitmap_data->data));
  ASSERT_LT(0, file_util::WriteFile(
      file_path,
      reinterpret_cast<const char*>(bitmap_data->front()),
      bitmap_data->size()));
}

TEST_F(RenderWidgetTest, FAILS_OnMsgPaintAtSize) {
  TestResizeAndPaint();
}
<|endoftext|>


<commit_before><commit_msg>using function pointer for better code readability<commit_after><|endoftext|>


<commit_before>#include <babylon/sprites/sprite_renderer.h>

#include <babylon/buffers/buffer.h>
#include <babylon/buffers/vertex_buffer.h>
#include <babylon/engines/constants.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>
#include <babylon/engines/thin_engine.h>
#include <babylon/materials/draw_wrapper.h>
#include <babylon/materials/effect.h>
#include <babylon/materials/ieffect_creation_options.h>
#include <babylon/materials/textures/thin_texture.h>
#include <babylon/sprites/thin_sprite.h>
#include <babylon/states/depth_culling_state.h>

namespace BABYLON {

SpriteRenderer::SpriteRenderer(ThinEngine* engine, size_t capacity, float epsilon, Scene* scene)
    : texture{nullptr}
    , cellWidth{0}
    , cellHeight{0}
    , blendMode{Constants::ALPHA_COMBINE}
    , autoResetAlpha{true}
    , disableDepthWrite{false}
    , fogEnabled{true}
    , capacity{this, &SpriteRenderer::get_capacity}
    , _engine{nullptr}
    , _useVAO{false}
    , _useInstancing{false}
    , _scene{nullptr}
    , _buffer{nullptr}
    , _spriteBuffer{nullptr}
    , _indexBuffer{nullptr}
    , _drawWrapperBase{nullptr}
    , _drawWrapperFog{nullptr}
    , _vertexArrayObject{nullptr}
{
  _capacity = capacity;
  _epsilon  = epsilon;

  _engine          = engine;
  _useInstancing   = engine->getCaps().instancedArrays;
  _useVAO          = engine->getCaps().vertexArrayObject && !engine->disableVertexArrayObjects;
  _scene           = scene;
  _drawWrapperBase = std::make_shared<DrawWrapper>(engine);
  _drawWrapperFog  = std::make_shared<DrawWrapper>(engine);

  if (!_useInstancing) {
    _buildIndexBuffer();
  }

  // VBO
  // 18 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV,
  // cellLeft, cellTop, cellWidth, cellHeight, color r, color g, color b, color a)
  // 16 when using instances
  _vertexBufferSize = _useInstancing ? 16 : 18;
  _vertexData       = Float32Array(capacity * _vertexBufferSize * (_useInstancing ? 1 : 4), 0.f);
  _buffer           = std::make_unique<Buffer>(engine, _vertexData, true, _vertexBufferSize);

  auto positions = _buffer->createVertexBuffer(VertexBuffer::PositionKind, 0, 4, _vertexBufferSize,
                                               _useInstancing);
  auto options   = _buffer->createVertexBuffer("options", 4, 2, _vertexBufferSize, _useInstancing);

  auto offset                           = 6ull;
  std::unique_ptr<VertexBuffer> offsets = nullptr;

  if (_useInstancing) {
    const Float32Array spriteData{0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f};
    _spriteBuffer = std::make_unique<Buffer>(engine, spriteData, false, 2);
    offsets       = _spriteBuffer->createVertexBuffer("offsets", 0, 2);
  }
  else {
    offsets = _buffer->createVertexBuffer("offsets", offset, 2, _vertexBufferSize, _useInstancing);
    offset += 2;
  }

  auto inverts
    = _buffer->createVertexBuffer("inverts", offset, 2, _vertexBufferSize, _useInstancing);
  auto cellInfo
    = _buffer->createVertexBuffer("cellInfo", offset + 2, 4, _vertexBufferSize, _useInstancing);
  auto colors = _buffer->createVertexBuffer(VertexBuffer::ColorKind, offset + 6, 4,
                                            _vertexBufferSize, _useInstancing);

  _vertexBuffers[VertexBuffer::PositionKind] = std::move(positions);
  _vertexBuffers[VertexBuffer::OptionsKind]  = std::move(options);
  _vertexBuffers[VertexBuffer::OffsetsKind]  = std::move(offsets);
  _vertexBuffers[VertexBuffer::InvertsKind]  = std::move(inverts);
  _vertexBuffers[VertexBuffer::CellInfoKind] = std::move(cellInfo);
  _vertexBuffers[VertexBuffer::ColorKind]    = std::move(colors);

  // Effects

  {
    IEffectCreationOptions spriteOptions;
    spriteOptions.attributes
      = {VertexBuffer::PositionKind, "options", "offsets", "inverts", "cellInfo",
         VertexBuffer::ColorKind};
    spriteOptions.uniformsNames = {"view", "projection", "textureInfos", "alphaTest"};
    spriteOptions.samplers      = {"diffuseSampler"};

    _drawWrapperBase->effect = _engine->createEffect("sprites", spriteOptions, _scene->getEngine());
  }

  if (_scene) {
    IEffectCreationOptions spriteOptions;
    spriteOptions.attributes
      = {VertexBuffer::PositionKind, "options", "offsets", "inverts", "cellInfo",
         VertexBuffer::ColorKind};
    spriteOptions.uniformsNames
      = {"view", "projection", "textureInfos", "alphaTest", "vFogInfos", "vFogColor"};
    spriteOptions.samplers = {"diffuseSampler"};
    spriteOptions.defines  = "#define FOG";

    _drawWrapperFog->effect
      = _scene->getEngine()->createEffect("sprites", spriteOptions, _scene->getEngine());
  }
}

SpriteRenderer::~SpriteRenderer() = default;

size_t SpriteRenderer::get_capacity() const
{
  return _capacity;
}

void SpriteRenderer::render(
  const std::vector<ThinSpritePtr>& sprites, float deltaTime, const Matrix& viewMatrix,
  const Matrix& projectionMatrix,
  const std::function<void(ThinSprite* sprite, const ISize& baseSize)>& customSpriteUpdate)
{
  if (!texture || !texture->isReady() || sprites.empty()) {
    return;
  }

  auto drawWrapper     = _drawWrapperBase;
  auto shouldRenderFog = false;
  if (fogEnabled && _scene && _scene->fogEnabled() && _scene->fogMode() != 0) {
    drawWrapper     = _drawWrapperFog;
    shouldRenderFog = true;
  }

  const auto& effect = drawWrapper->effect;

  // Check
  if (!effect || !effect->isReady()) {
    return;
  }
  auto engine                     = _scene->getEngine();
  const auto useRightHandedSystem = !!(_scene && _scene->useRightHandedSystem());
  const auto baseSize             = texture->getBaseSize();

  // Sprites
  auto max = std::min(_capacity, sprites.size());

  auto offset   = 0u;
  auto noSprite = true;
  for (size_t index = 0; index < max; index++) {
    const auto& sprite = sprites[index];
    if (!sprite || !sprite->isVisible) {
      continue;
    }

    noSprite = false;
    sprite->_animate(deltaTime);

    _appendSpriteVertex(offset++, sprite, 0, 0, baseSize, useRightHandedSystem, customSpriteUpdate);
    if (!_useInstancing) {
      _appendSpriteVertex(offset++, sprite, 1, 0, baseSize, useRightHandedSystem,
                          customSpriteUpdate);
      _appendSpriteVertex(offset++, sprite, 1, 1, baseSize, useRightHandedSystem,
                          customSpriteUpdate);
      _appendSpriteVertex(offset++, sprite, 0, 1, baseSize, useRightHandedSystem,
                          customSpriteUpdate);
    }
  }

  if (noSprite) {
    return;
  }

  _buffer->update(_vertexData);

  const auto culling = engine->depthCullingState()->cull().value_or(true);
  const auto zOffset = engine->depthCullingState()->zOffset();

  // Handle Right Handed
  if (useRightHandedSystem && _scene) {
    _scene->getEngine()->setState(culling, zOffset, false, false);
  }

  // Render
  engine->enableEffect(drawWrapper);

  effect->setTexture("diffuseSampler", texture);
  effect->setMatrix("view", viewMatrix);
  effect->setMatrix("projection", projectionMatrix);

  // Scene Info
  if (shouldRenderFog && _scene) {
    const auto scene = _scene;

    // Fog
    effect->setFloat4("vFogInfos", static_cast<float>(scene->fogMode()), scene->fogStart,
                      scene->fogEnd, scene->fogDensity);
    effect->setColor3("vFogColor", scene->fogColor);
  }

  if (_useVAO) {
    if (!_vertexArrayObject) {
      _vertexArrayObject = engine->recordVertexArrayObject(_vertexBuffers, _indexBuffer, effect);
    }
    engine->bindVertexArrayObject(_vertexArrayObject, _indexBuffer);
  }
  else {
    // VBOs
    engine->bindBuffers(_vertexBuffers, _indexBuffer, effect);
  }

  // Draw order
  engine->depthCullingState()->depthFunc = Constants::LEQUAL;
  if (!disableDepthWrite) {
    effect->setBool("alphaTest", true);
    engine->setColorWrite(false);
    if (_useInstancing) {
      engine->drawArraysType(Constants::MATERIAL_TriangleStripDrawMode, 0, 4, offset);
    }
    else {
      engine->drawElementsType(Constants::MATERIAL_TriangleFillMode, 0, (offset / 4) * 6);
    }
    engine->setColorWrite(true);
    effect->setBool("alphaTest", false);
  }

  engine->setAlphaMode(blendMode);
  if (_useInstancing) {
    engine->drawArraysType(Constants::MATERIAL_TriangleStripDrawMode, 0, 4, offset);
  }
  else {
    engine->drawElementsType(Constants::MATERIAL_TriangleFillMode, 0, (offset / 4) * 6);
  }

  if (autoResetAlpha) {
    engine->setAlphaMode(Constants::ALPHA_DISABLE);
  }

  // Restore Right Handed
  if (useRightHandedSystem && _scene) {
    _scene->getEngine()->setState(culling, zOffset, false, true);
  }

  engine->unbindInstanceAttributes();
}

void SpriteRenderer::_appendSpriteVertex(
  size_t index, const ThinSpritePtr& sprite, int offsetX, int offsetY, const ISize& baseSize,
  bool useRightHandedSystem,
  const std::function<void(ThinSprite* sprite, const ISize& baseSize)>& customSpriteUpdate)
{
  size_t arrayOffset = index * _vertexBufferSize;

  auto offsetXVal = static_cast<float>(offsetX);
  auto offsetYVal = static_cast<float>(offsetY);

  if (offsetX == 0) {
    offsetXVal = _epsilon;
  }
  else if (offsetX == 1) {
    offsetXVal = 1.f - _epsilon;
  }

  if (offsetY == 0) {
    offsetYVal = _epsilon;
  }
  else if (offsetY == 1) {
    offsetYVal = 1.f - _epsilon;
  }

  if (customSpriteUpdate) {
    customSpriteUpdate(sprite.get(), baseSize);
  }
  else {
    if (!sprite->cellIndex) {
      sprite->cellIndex = 0;
    }

    const auto rowSize = baseSize.width / cellWidth;
    const auto offset  = (sprite->cellIndex / rowSize) >> 0;
    sprite->_xOffset   = (sprite->cellIndex - offset * rowSize) * cellWidth / baseSize.width;
    sprite->_yOffset   = offset * cellHeight / baseSize.height;
    sprite->_xSize     = cellWidth;
    sprite->_ySize     = cellHeight;
  }

  // Positions
  _vertexData[arrayOffset + 0] = sprite->position.x;
  _vertexData[arrayOffset + 1] = sprite->position.y;
  _vertexData[arrayOffset + 2] = sprite->position.z;
  _vertexData[arrayOffset + 3] = sprite->angle;
  // Options
  _vertexData[arrayOffset + 4] = static_cast<float>(sprite->width);
  _vertexData[arrayOffset + 5] = static_cast<float>(sprite->height);

  if (!_useInstancing) {
    _vertexData[arrayOffset + 6] = offsetXVal;
    _vertexData[arrayOffset + 7] = offsetYVal;
  }
  else {
    arrayOffset -= 2;
  }

  // Inverts according to Right Handed
  if (useRightHandedSystem) {
    _vertexData[arrayOffset + 8] = sprite->invertU ? 0.f : 1.f;
  }
  else {
    _vertexData[arrayOffset + 8] = sprite->invertU ? 1.f : 0.f;
  }

  _vertexData[arrayOffset + 9] = sprite->invertV ? 1.f : 0.f;

  _vertexData[arrayOffset + 10] = static_cast<float>(sprite->_xOffset);
  _vertexData[arrayOffset + 11] = static_cast<float>(sprite->_yOffset);
  _vertexData[arrayOffset + 12] = static_cast<float>(sprite->_xSize) / baseSize.width;
  _vertexData[arrayOffset + 13] = static_cast<float>(sprite->_ySize) / baseSize.height;

  // Color
  _vertexData[arrayOffset + 14] = sprite->color.r;
  _vertexData[arrayOffset + 15] = sprite->color.g;
  _vertexData[arrayOffset + 16] = sprite->color.b;
  _vertexData[arrayOffset + 17] = sprite->color.a;
}

void SpriteRenderer::_buildIndexBuffer()
{
  IndicesArray indices;
  auto index = 0;
  for (unsigned int count = 0; count < capacity; ++count) {
    indices.emplace_back(index + 0);
    indices.emplace_back(index + 1);
    indices.emplace_back(index + 2);
    indices.emplace_back(index + 0);
    indices.emplace_back(index + 2);
    indices.emplace_back(index + 3);
    index += 4;
  }

  _indexBuffer = _engine->createIndexBuffer(indices);
}

void SpriteRenderer::rebuild()
{
  if (_indexBuffer) {
    _buildIndexBuffer();
  }

  if (_useVAO) {
    _vertexArrayObject = nullptr;
  }

  _buffer->_rebuild();

  for (const auto& [name, vertexBuffer] : _vertexBuffers) {
    vertexBuffer->_rebuild();
  }

  if (_spriteBuffer) {
    _spriteBuffer->_rebuild();
  }
}

void SpriteRenderer::dispose()
{
  if (_buffer) {
    _buffer->dispose();
    _buffer = nullptr;
  }

  if (_spriteBuffer) {
    _spriteBuffer->dispose();
    _spriteBuffer = nullptr;
  }

  if (_indexBuffer) {
    _engine->_releaseBuffer(_indexBuffer);
    _indexBuffer = nullptr;
  }

  if (_vertexArrayObject) {
    _engine->releaseVertexArrayObject(_vertexArrayObject);
    _vertexArrayObject = nullptr;
  }

  if (texture) {
    texture->dispose();
    texture = nullptr;
  }
}

} // end of namespace BABYLON
<commit_msg>Setting depthFunc based on reverse depth buffer flag<commit_after>#include <babylon/sprites/sprite_renderer.h>

#include <babylon/buffers/buffer.h>
#include <babylon/buffers/vertex_buffer.h>
#include <babylon/engines/constants.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>
#include <babylon/engines/thin_engine.h>
#include <babylon/materials/draw_wrapper.h>
#include <babylon/materials/effect.h>
#include <babylon/materials/ieffect_creation_options.h>
#include <babylon/materials/textures/thin_texture.h>
#include <babylon/sprites/thin_sprite.h>
#include <babylon/states/depth_culling_state.h>

namespace BABYLON {

SpriteRenderer::SpriteRenderer(ThinEngine* engine, size_t capacity, float epsilon, Scene* scene)
    : texture{nullptr}
    , cellWidth{0}
    , cellHeight{0}
    , blendMode{Constants::ALPHA_COMBINE}
    , autoResetAlpha{true}
    , disableDepthWrite{false}
    , fogEnabled{true}
    , capacity{this, &SpriteRenderer::get_capacity}
    , _engine{nullptr}
    , _useVAO{false}
    , _useInstancing{false}
    , _scene{nullptr}
    , _buffer{nullptr}
    , _spriteBuffer{nullptr}
    , _indexBuffer{nullptr}
    , _drawWrapperBase{nullptr}
    , _drawWrapperFog{nullptr}
    , _vertexArrayObject{nullptr}
{
  _capacity = capacity;
  _epsilon  = epsilon;

  _engine          = engine;
  _useInstancing   = engine->getCaps().instancedArrays;
  _useVAO          = engine->getCaps().vertexArrayObject && !engine->disableVertexArrayObjects;
  _scene           = scene;
  _drawWrapperBase = std::make_shared<DrawWrapper>(engine);
  _drawWrapperFog  = std::make_shared<DrawWrapper>(engine);

  if (!_useInstancing) {
    _buildIndexBuffer();
  }

  // VBO
  // 18 floats per sprite (x, y, z, angle, sizeX, sizeY, offsetX, offsetY, invertU, invertV,
  // cellLeft, cellTop, cellWidth, cellHeight, color r, color g, color b, color a)
  // 16 when using instances
  _vertexBufferSize = _useInstancing ? 16 : 18;
  _vertexData       = Float32Array(capacity * _vertexBufferSize * (_useInstancing ? 1 : 4), 0.f);
  _buffer           = std::make_unique<Buffer>(engine, _vertexData, true, _vertexBufferSize);

  auto positions = _buffer->createVertexBuffer(VertexBuffer::PositionKind, 0, 4, _vertexBufferSize,
                                               _useInstancing);
  auto options   = _buffer->createVertexBuffer("options", 4, 2, _vertexBufferSize, _useInstancing);

  auto offset                           = 6ull;
  std::unique_ptr<VertexBuffer> offsets = nullptr;

  if (_useInstancing) {
    const Float32Array spriteData{0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f};
    _spriteBuffer = std::make_unique<Buffer>(engine, spriteData, false, 2);
    offsets       = _spriteBuffer->createVertexBuffer("offsets", 0, 2);
  }
  else {
    offsets = _buffer->createVertexBuffer("offsets", offset, 2, _vertexBufferSize, _useInstancing);
    offset += 2;
  }

  auto inverts
    = _buffer->createVertexBuffer("inverts", offset, 2, _vertexBufferSize, _useInstancing);
  auto cellInfo
    = _buffer->createVertexBuffer("cellInfo", offset + 2, 4, _vertexBufferSize, _useInstancing);
  auto colors = _buffer->createVertexBuffer(VertexBuffer::ColorKind, offset + 6, 4,
                                            _vertexBufferSize, _useInstancing);

  _vertexBuffers[VertexBuffer::PositionKind] = std::move(positions);
  _vertexBuffers[VertexBuffer::OptionsKind]  = std::move(options);
  _vertexBuffers[VertexBuffer::OffsetsKind]  = std::move(offsets);
  _vertexBuffers[VertexBuffer::InvertsKind]  = std::move(inverts);
  _vertexBuffers[VertexBuffer::CellInfoKind] = std::move(cellInfo);
  _vertexBuffers[VertexBuffer::ColorKind]    = std::move(colors);

  // Effects

  {
    IEffectCreationOptions spriteOptions;
    spriteOptions.attributes
      = {VertexBuffer::PositionKind, "options", "offsets", "inverts", "cellInfo",
         VertexBuffer::ColorKind};
    spriteOptions.uniformsNames = {"view", "projection", "textureInfos", "alphaTest"};
    spriteOptions.samplers      = {"diffuseSampler"};

    _drawWrapperBase->effect = _engine->createEffect("sprites", spriteOptions, _scene->getEngine());
  }

  if (_scene) {
    IEffectCreationOptions spriteOptions;
    spriteOptions.attributes
      = {VertexBuffer::PositionKind, "options", "offsets", "inverts", "cellInfo",
         VertexBuffer::ColorKind};
    spriteOptions.uniformsNames
      = {"view", "projection", "textureInfos", "alphaTest", "vFogInfos", "vFogColor"};
    spriteOptions.samplers = {"diffuseSampler"};
    spriteOptions.defines  = "#define FOG";

    _drawWrapperFog->effect
      = _scene->getEngine()->createEffect("sprites", spriteOptions, _scene->getEngine());
  }
}

SpriteRenderer::~SpriteRenderer() = default;

size_t SpriteRenderer::get_capacity() const
{
  return _capacity;
}

void SpriteRenderer::render(
  const std::vector<ThinSpritePtr>& sprites, float deltaTime, const Matrix& viewMatrix,
  const Matrix& projectionMatrix,
  const std::function<void(ThinSprite* sprite, const ISize& baseSize)>& customSpriteUpdate)
{
  if (!texture || !texture->isReady() || sprites.empty()) {
    return;
  }

  auto drawWrapper     = _drawWrapperBase;
  auto shouldRenderFog = false;
  if (fogEnabled && _scene && _scene->fogEnabled() && _scene->fogMode() != 0) {
    drawWrapper     = _drawWrapperFog;
    shouldRenderFog = true;
  }

  const auto& effect = drawWrapper->effect;

  // Check
  if (!effect || !effect->isReady()) {
    return;
  }
  auto engine                     = _scene->getEngine();
  const auto useRightHandedSystem = !!(_scene && _scene->useRightHandedSystem());
  const auto baseSize             = texture->getBaseSize();

  // Sprites
  auto max = std::min(_capacity, sprites.size());

  auto offset   = 0u;
  auto noSprite = true;
  for (size_t index = 0; index < max; index++) {
    const auto& sprite = sprites[index];
    if (!sprite || !sprite->isVisible) {
      continue;
    }

    noSprite = false;
    sprite->_animate(deltaTime);

    _appendSpriteVertex(offset++, sprite, 0, 0, baseSize, useRightHandedSystem, customSpriteUpdate);
    if (!_useInstancing) {
      _appendSpriteVertex(offset++, sprite, 1, 0, baseSize, useRightHandedSystem,
                          customSpriteUpdate);
      _appendSpriteVertex(offset++, sprite, 1, 1, baseSize, useRightHandedSystem,
                          customSpriteUpdate);
      _appendSpriteVertex(offset++, sprite, 0, 1, baseSize, useRightHandedSystem,
                          customSpriteUpdate);
    }
  }

  if (noSprite) {
    return;
  }

  _buffer->update(_vertexData);

  const auto culling = engine->depthCullingState()->cull().value_or(true);
  const auto zOffset = engine->depthCullingState()->zOffset();

  engine->setState(culling, zOffset, false, false);

  // Render
  engine->enableEffect(drawWrapper);

  effect->setTexture("diffuseSampler", texture);
  effect->setMatrix("view", viewMatrix);
  effect->setMatrix("projection", projectionMatrix);

  // Scene Info
  if (shouldRenderFog && _scene) {
    const auto scene = _scene;

    // Fog
    effect->setFloat4("vFogInfos", static_cast<float>(scene->fogMode()), scene->fogStart,
                      scene->fogEnd, scene->fogDensity);
    effect->setColor3("vFogColor", scene->fogColor);
  }

  if (_useVAO) {
    if (!_vertexArrayObject) {
      _vertexArrayObject = engine->recordVertexArrayObject(_vertexBuffers, _indexBuffer, effect);
    }
    engine->bindVertexArrayObject(_vertexArrayObject, _indexBuffer);
  }
  else {
    // VBOs
    engine->bindBuffers(_vertexBuffers, _indexBuffer, effect);
  }

  // Draw order
  engine->depthCullingState()->depthFunc
    = engine->useReverseDepthBuffer ? Constants::GEQUAL : Constants::LEQUAL;
  if (!disableDepthWrite) {
    effect->setBool("alphaTest", true);
    engine->setColorWrite(false);
    if (_useInstancing) {
      engine->drawArraysType(Constants::MATERIAL_TriangleStripDrawMode, 0, 4, offset);
    }
    else {
      engine->drawElementsType(Constants::MATERIAL_TriangleFillMode, 0, (offset / 4) * 6);
    }
    engine->setColorWrite(true);
    effect->setBool("alphaTest", false);
  }

  engine->setAlphaMode(blendMode);
  if (_useInstancing) {
    engine->drawArraysType(Constants::MATERIAL_TriangleStripDrawMode, 0, 4, offset);
  }
  else {
    engine->drawElementsType(Constants::MATERIAL_TriangleFillMode, 0, (offset / 4) * 6);
  }

  if (autoResetAlpha) {
    engine->setAlphaMode(Constants::ALPHA_DISABLE);
  }

  // Restore Right Handed
  if (useRightHandedSystem && _scene) {
    _scene->getEngine()->setState(culling, zOffset, false, true);
  }

  engine->unbindInstanceAttributes();
}

void SpriteRenderer::_appendSpriteVertex(
  size_t index, const ThinSpritePtr& sprite, int offsetX, int offsetY, const ISize& baseSize,
  bool useRightHandedSystem,
  const std::function<void(ThinSprite* sprite, const ISize& baseSize)>& customSpriteUpdate)
{
  size_t arrayOffset = index * _vertexBufferSize;

  auto offsetXVal = static_cast<float>(offsetX);
  auto offsetYVal = static_cast<float>(offsetY);

  if (offsetX == 0) {
    offsetXVal = _epsilon;
  }
  else if (offsetX == 1) {
    offsetXVal = 1.f - _epsilon;
  }

  if (offsetY == 0) {
    offsetYVal = _epsilon;
  }
  else if (offsetY == 1) {
    offsetYVal = 1.f - _epsilon;
  }

  if (customSpriteUpdate) {
    customSpriteUpdate(sprite.get(), baseSize);
  }
  else {
    if (!sprite->cellIndex) {
      sprite->cellIndex = 0;
    }

    const auto rowSize = baseSize.width / cellWidth;
    const auto offset  = (sprite->cellIndex / rowSize) >> 0;
    sprite->_xOffset   = (sprite->cellIndex - offset * rowSize) * cellWidth / baseSize.width;
    sprite->_yOffset   = offset * cellHeight / baseSize.height;
    sprite->_xSize     = cellWidth;
    sprite->_ySize     = cellHeight;
  }

  // Positions
  _vertexData[arrayOffset + 0] = sprite->position.x;
  _vertexData[arrayOffset + 1] = sprite->position.y;
  _vertexData[arrayOffset + 2] = sprite->position.z;
  _vertexData[arrayOffset + 3] = sprite->angle;
  // Options
  _vertexData[arrayOffset + 4] = static_cast<float>(sprite->width);
  _vertexData[arrayOffset + 5] = static_cast<float>(sprite->height);

  if (!_useInstancing) {
    _vertexData[arrayOffset + 6] = offsetXVal;
    _vertexData[arrayOffset + 7] = offsetYVal;
  }
  else {
    arrayOffset -= 2;
  }

  // Inverts according to Right Handed
  if (useRightHandedSystem) {
    _vertexData[arrayOffset + 8] = sprite->invertU ? 0.f : 1.f;
  }
  else {
    _vertexData[arrayOffset + 8] = sprite->invertU ? 1.f : 0.f;
  }

  _vertexData[arrayOffset + 9] = sprite->invertV ? 1.f : 0.f;

  _vertexData[arrayOffset + 10] = static_cast<float>(sprite->_xOffset);
  _vertexData[arrayOffset + 11] = static_cast<float>(sprite->_yOffset);
  _vertexData[arrayOffset + 12] = static_cast<float>(sprite->_xSize) / baseSize.width;
  _vertexData[arrayOffset + 13] = static_cast<float>(sprite->_ySize) / baseSize.height;

  // Color
  _vertexData[arrayOffset + 14] = sprite->color.r;
  _vertexData[arrayOffset + 15] = sprite->color.g;
  _vertexData[arrayOffset + 16] = sprite->color.b;
  _vertexData[arrayOffset + 17] = sprite->color.a;
}

void SpriteRenderer::_buildIndexBuffer()
{
  IndicesArray indices;
  auto index = 0;
  for (unsigned int count = 0; count < capacity; ++count) {
    indices.emplace_back(index + 0);
    indices.emplace_back(index + 1);
    indices.emplace_back(index + 2);
    indices.emplace_back(index + 0);
    indices.emplace_back(index + 2);
    indices.emplace_back(index + 3);
    index += 4;
  }

  _indexBuffer = _engine->createIndexBuffer(indices);
}

void SpriteRenderer::rebuild()
{
  if (_indexBuffer) {
    _buildIndexBuffer();
  }

  if (_useVAO) {
    _vertexArrayObject = nullptr;
  }

  _buffer->_rebuild();

  for (const auto& [name, vertexBuffer] : _vertexBuffers) {
    vertexBuffer->_rebuild();
  }

  if (_spriteBuffer) {
    _spriteBuffer->_rebuild();
  }
}

void SpriteRenderer::dispose()
{
  if (_buffer) {
    _buffer->dispose();
    _buffer = nullptr;
  }

  if (_spriteBuffer) {
    _spriteBuffer->dispose();
    _spriteBuffer = nullptr;
  }

  if (_indexBuffer) {
    _engine->_releaseBuffer(_indexBuffer);
    _indexBuffer = nullptr;
  }

  if (_vertexArrayObject) {
    _engine->releaseVertexArrayObject(_vertexArrayObject);
    _vertexArrayObject = nullptr;
  }

  if (texture) {
    texture->dispose();
    texture = nullptr;
  }
}

} // end of namespace BABYLON
<|endoftext|>


<commit_before>/*!
	@file
	@author		Albert Semenov
	@date		11/2009
	@module
*/

#include "ResourceW32Pointer.h"
#include <windows.h>

namespace input
{

	ResourceW32Pointer::ResourceW32Pointer() :
		mHandle(0)
	{
	}

	void ResourceW32Pointer::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version)
	{
		Base::deserialization(_node, _version);

		MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator();
		while (info.next())
		{
			if (info->getName() == "Property")
			{
				const std::string& key = info->findAttribute("key");

				if (key == "SourceFile")
				{
					std::string path = MyGUI::DataManager::getInstance().getDataPath(info->getContent());
					mHandle = (size_t)LoadCursorFromFileA(path.c_str());
				}
				else if (key == "SourceSystem")
				{
					std::string value = info->getContent();
					if (value == "IDC_ARROW")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
					else if (value == "IDC_IBEAM")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_IBEAM));
					else if (value == "IDC_WAIT")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
					else if (value == "IDC_CROSS")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_CROSS));
					else if (value == "IDC_UPARROW")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_UPARROW));
					else if (value == "IDC_SIZE")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZE));
					else if (value == "IDC_ICON")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ICON));
					else if (value == "IDC_SIZENWSE")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENWSE));
					else if (value == "IDC_SIZENESW")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENESW));
					else if (value == "IDC_SIZEWE")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE));
					else if (value == "IDC_SIZENS")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENS));
					else if (value == "IDC_SIZEALL")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEALL));
					else if (value == "IDC_NO")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_NO));
					else if (value == "IDC_HAND")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND));
					else if (value == "IDC_APPSTARTING")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_APPSTARTING));
					else if (value == "IDC_HELP")
						mHandle = (size_t)::LoadCursor(NULL, MAKEINTRESOURCE(IDC_HELP));
				}
			}
		}
	}

}
<commit_msg>fix LoadCursor calls<commit_after>/*!
	@file
	@author		Albert Semenov
	@date		11/2009
	@module
*/

#include "ResourceW32Pointer.h"
#include <windows.h>

namespace input
{

	ResourceW32Pointer::ResourceW32Pointer() :
		mHandle(0)
	{
	}

	void ResourceW32Pointer::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version)
	{
		Base::deserialization(_node, _version);

		MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator();
		while (info.next())
		{
			if (info->getName() == "Property")
			{
				const std::string& key = info->findAttribute("key");

				if (key == "SourceFile")
				{
					std::string path = MyGUI::DataManager::getInstance().getDataPath(info->getContent());
					mHandle = (size_t)LoadCursorFromFileA(path.c_str());
				}
				else if (key == "SourceSystem")
				{
					std::string value = info->getContent();
					if (value == "IDC_ARROW")
						mHandle = (size_t)::LoadCursor(NULL, IDC_ARROW);
					else if (value == "IDC_IBEAM")
						mHandle = (size_t)::LoadCursor(NULL, IDC_IBEAM);
					else if (value == "IDC_WAIT")
						mHandle = (size_t)::LoadCursor(NULL, IDC_WAIT);
					else if (value == "IDC_CROSS")
						mHandle = (size_t)::LoadCursor(NULL, IDC_CROSS);
					else if (value == "IDC_UPARROW")
						mHandle = (size_t)::LoadCursor(NULL, IDC_UPARROW);
					else if (value == "IDC_SIZE")
						mHandle = (size_t)::LoadCursor(NULL, IDC_SIZE);
					else if (value == "IDC_ICON")
						mHandle = (size_t)::LoadCursor(NULL, IDC_ICON);
					else if (value == "IDC_SIZENWSE")
						mHandle = (size_t)::LoadCursor(NULL, IDC_SIZENWSE);
					else if (value == "IDC_SIZENESW")
						mHandle = (size_t)::LoadCursor(NULL, IDC_SIZENESW);
					else if (value == "IDC_SIZEWE")
						mHandle = (size_t)::LoadCursor(NULL, IDC_SIZEWE);
					else if (value == "IDC_SIZENS")
						mHandle = (size_t)::LoadCursor(NULL, IDC_SIZENS);
					else if (value == "IDC_SIZEALL")
						mHandle = (size_t)::LoadCursor(NULL, IDC_SIZEALL);
					else if (value == "IDC_NO")
						mHandle = (size_t)::LoadCursor(NULL, IDC_NO);
					else if (value == "IDC_HAND")
						mHandle = (size_t)::LoadCursor(NULL, IDC_HAND);
					else if (value == "IDC_APPSTARTING")
						mHandle = (size_t)::LoadCursor(NULL, IDC_APPSTARTING);
					else if (value == "IDC_HELP")
						mHandle = (size_t)::LoadCursor(NULL, IDC_HELP);
				}
			}
		}
	}

}
<|endoftext|>