<commit_before>#define EXTERN_DLL_EXPORT

#include <windows.h>
#include <Psapi.h>
#include <tlhelp32.h>
#include <vector>
#include <algorithm>

#include <beaengine/BeaEngine.h>

const int PATH_MAXIMUM_LENGTH = 260;

enum class RequestFunction
{
	IsProcessValid,
	OpenRemoteProcess,
	CloseRemoteProcess,
	ReadRemoteMemory,
	WriteRemoteMemory,
	EnumerateProcesses,
	EnumerateRemoteSectionsAndModules
};

typedef LPVOID(__stdcall *RequestFunctionPtrCallback)(RequestFunction request);
RequestFunctionPtrCallback requestFunction;

EXTERN_DLL_EXPORT VOID __stdcall Initialize(RequestFunctionPtrCallback requestCallback)
{
	requestFunction = requestCallback;
}

DWORD lastError = 0;
EXTERN_DLL_EXPORT DWORD __stdcall GetLastErrorCode()
{
	return lastError;
}

EXTERN_DLL_EXPORT BOOL __stdcall IsProcessValid(HANDLE process)
{
	if (!process)
	{
		return FALSE;
	}

	auto retn = WaitForSingleObject(process, 0);
	if (retn == WAIT_FAILED)
	{
		return FALSE;
	}
	return retn == WAIT_TIMEOUT;
}

EXTERN_DLL_EXPORT LPVOID __stdcall OpenRemoteProcess(DWORD pid, DWORD desiredAccess)
{
	return OpenProcess(desiredAccess, FALSE, pid);
}

EXTERN_DLL_EXPORT VOID __stdcall CloseRemoteProcess(HANDLE process)
{
	CloseHandle(process);
}

EXTERN_DLL_EXPORT BOOL __stdcall ReadRemoteMemory(HANDLE process, LPCVOID address, LPVOID buffer, SIZE_T size)
{
	if (ReadProcessMemory(process, address, buffer, size, nullptr))
	{
		lastError = 0;

		return TRUE;
	}

	lastError = GetLastError();

	return FALSE;
}

EXTERN_DLL_EXPORT BOOL __stdcall WriteRemoteMemory(HANDLE process, LPVOID address, LPCVOID buffer, SIZE_T size)
{
	DWORD oldProtect;
	if (VirtualProtectEx(process, address, size, PAGE_EXECUTE_READWRITE, &oldProtect))
	{
		if (WriteProcessMemory(process, address, buffer, size, nullptr))
		{
			VirtualProtectEx(process, address, size, oldProtect, nullptr);

			lastError = 0;

			return TRUE;
		}
	}

	lastError = GetLastError();

	return FALSE;
}

enum class Platform
{
	Unknown,
	X86,
	X64
};

Platform GetProcessPlatform(HANDLE process)
{
	auto GetProcessorArchitecture = []()
	{
		static USHORT processorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
		if (processorArchitecture == PROCESSOR_ARCHITECTURE_UNKNOWN)
		{
			SYSTEM_INFO info = {};
			GetNativeSystemInfo(&info);

			processorArchitecture = info.wProcessorArchitecture;
		}
		return processorArchitecture;
	};

	switch (GetProcessorArchitecture())
	{
		case PROCESSOR_ARCHITECTURE_INTEL:
			return Platform::X86;
		case PROCESSOR_ARCHITECTURE_AMD64:
			BOOL isWow64 = FALSE;
			if (IsWow64Process(process, &isWow64))
			{
				return isWow64 ? Platform::X86 : Platform::X64;
			}

#ifdef _WIN64
			return Platform::X64;
#else
			return Platform::X86;
#endif
	}
	return Platform::Unknown;
}

typedef VOID(__stdcall EnumerateProcessCallback)(DWORD pid, WCHAR modulePath[PATH_MAXIMUM_LENGTH]);

EXTERN_DLL_EXPORT VOID __stdcall EnumerateProcesses(EnumerateProcessCallback callbackProcess)
{
	if (callbackProcess == nullptr)
	{
		return;
	}

	auto handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (handle != INVALID_HANDLE_VALUE)
	{
		PROCESSENTRY32W pe32 = {};
		pe32.dwSize = sizeof(PROCESSENTRY32W);
		if (Process32FirstW(handle, &pe32))
		{
			auto openRemoteProcess = reinterpret_cast<decltype(OpenRemoteProcess)*>(requestFunction(RequestFunction::OpenRemoteProcess));
			auto closeRemoteProcess = reinterpret_cast<decltype(CloseRemoteProcess)*>(requestFunction(RequestFunction::CloseRemoteProcess));

			do
			{
				auto process = openRemoteProcess(pe32.th32ProcessID, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ);
				if (process != nullptr && process != INVALID_HANDLE_VALUE)
				{
					auto platform = GetProcessPlatform(process);

#ifdef _WIN64
					if (platform == Platform::X64)
#else
					if (platform == Platform::X86)
#endif
					{
						WCHAR process_path[MAX_PATH] = { };
						GetModuleFileNameExW(process, NULL, process_path, MAX_PATH);

						callbackProcess(pe32.th32ProcessID, process_path);
					}

					closeRemoteProcess(process);
				}
			} while (Process32NextW(handle, &pe32));
		}

		CloseHandle(handle);

		lastError = 0;

		return;
	}

	lastError = GetLastError();
}

typedef VOID(__stdcall EnumerateRemoteSectionsCallback)(LPVOID baseAddress, SIZE_T regionSize, BYTE name[IMAGE_SIZEOF_SHORT_NAME + 2], DWORD state, DWORD protection, DWORD type, WCHAR modulePath[PATH_MAXIMUM_LENGTH]);
typedef VOID(__stdcall EnumerateRemoteModulesCallback)(LPVOID baseAddress, SIZE_T regionSize, WCHAR modulePath[PATH_MAXIMUM_LENGTH]);

EXTERN_DLL_EXPORT VOID __stdcall EnumerateRemoteSectionsAndModules(HANDLE process, EnumerateRemoteSectionsCallback callbackSection, EnumerateRemoteModulesCallback callbackModule)
{
	if (callbackSection == nullptr && callbackModule == nullptr)
	{
		return;
	}

	struct SectionInfo
	{
		LPVOID BaseAddress;
		SIZE_T RegionSize;
		BYTE Name[IMAGE_SIZEOF_SHORT_NAME + 2];
		DWORD State;
		DWORD Protection;
		DWORD Type;
		WCHAR ModulePath[PATH_MAXIMUM_LENGTH];
	};
	std::vector<SectionInfo> sections;

	SYSTEM_INFO sysInfo;
	GetSystemInfo(&sysInfo);

	MEMORY_BASIC_INFORMATION memInfo;
	size_t address = (size_t)sysInfo.lpMinimumApplicationAddress;
	while (address < (size_t)sysInfo.lpMaximumApplicationAddress)
	{
		if (VirtualQueryEx(process, (LPCVOID)address, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) != 0)
		{
			if (memInfo.State == MEM_COMMIT /*&& memInfo.Type == MEM_PRIVATE*/)
			{
				SectionInfo section = {};
				section.BaseAddress = memInfo.BaseAddress;
				section.RegionSize = memInfo.RegionSize;
				section.State = memInfo.State;
				section.Protection = memInfo.Protect;
				section.Type = memInfo.Type;

				sections.push_back(std::move(section));
			}
			address = (ULONG_PTR)memInfo.BaseAddress + memInfo.RegionSize;
		}
		else
		{
			address += 1024;
		}
	}

	auto handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(process));
	if (handle != INVALID_HANDLE_VALUE)
	{
		MODULEENTRY32W me32 = {};
		me32.dwSize = sizeof(MODULEENTRY32W);
		if (Module32FirstW(handle, &me32))
		{
			auto readRemoteMemory = reinterpret_cast<decltype(ReadRemoteMemory)*>(requestFunction(RequestFunction::ReadRemoteMemory));

			do
			{
				if (callbackModule != nullptr)
				{
					callbackModule(me32.modBaseAddr, me32.modBaseSize, me32.szExePath);
				}

				if (callbackSection != nullptr)
				{
					auto it = std::lower_bound(std::begin(sections), std::end(sections), (LPVOID)me32.modBaseAddr, [&sections](const SectionInfo& lhs, const LPVOID& rhs)
					{
						return lhs.BaseAddress < rhs;
					});

					IMAGE_DOS_HEADER DosHdr = {};
					IMAGE_NT_HEADERS NtHdr = {};

					readRemoteMemory(process, me32.modBaseAddr, &DosHdr, sizeof(IMAGE_DOS_HEADER));
					readRemoteMemory(process, me32.modBaseAddr + DosHdr.e_lfanew, &NtHdr, sizeof(IMAGE_NT_HEADERS));

					std::vector<IMAGE_SECTION_HEADER> sectionHeaders(NtHdr.FileHeader.NumberOfSections);
					readRemoteMemory(process, me32.modBaseAddr + DosHdr.e_lfanew + sizeof(IMAGE_NT_HEADERS), sectionHeaders.data(), NtHdr.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
					for (int i = 0; i < NtHdr.FileHeader.NumberOfSections; ++i)
					{
						auto&& section = sectionHeaders[i];

						auto sectionAddress = (size_t)me32.modBaseAddr + section.VirtualAddress;
						for (auto j = it; j != std::end(sections); ++j)
						{
							if (sectionAddress >= (size_t)j->BaseAddress && sectionAddress <= (size_t)j->BaseAddress + (size_t)j->RegionSize)
							{
								std::memcpy(j->Name, section.Name, IMAGE_SIZEOF_SHORT_NAME);
								std::memcpy(j->ModulePath, me32.szExePath, sizeof(SectionInfo::ModulePath));
								break;
							}
						}

					}
				}
			} while (Module32NextW(handle, &me32));
		}

		CloseHandle(handle);

		if (callbackSection != nullptr)
		{
			for (auto&& section : sections)
			{
				callbackSection(section.BaseAddress, section.RegionSize, section.Name, section.State, section.Protection, section.Type, section.ModulePath);
			}
		}

		lastError = 0;

		return;
	}

	lastError = GetLastError();
}

typedef VOID(__stdcall DisassembleRemoteCodeCallback)(LPVOID address, DWORD length, CHAR instruction[64]);

EXTERN_DLL_EXPORT VOID __stdcall DisassembleRemoteCode(HANDLE process, LPVOID address, int length, DisassembleRemoteCodeCallback callbackDisassembledCode)
{
	if (callbackDisassembledCode == nullptr)
	{
		return;
	}

	UIntPtr start = (UIntPtr)address;
	UIntPtr end = start + length;
	if (end <= start)
	{
		return;
	}

	DISASM disasm;
	std::memset(&disasm, 0, sizeof(DISASM));
	disasm.Options = NasmSyntax + PrefixedNumeral;
#ifdef _WIN64
	disasm.Archi = 64;
#endif

	auto readRemoteMemory = reinterpret_cast<decltype(ReadRemoteMemory)*>(requestFunction(RequestFunction::ReadRemoteMemory));

	std::vector<uint8_t> buffer(length);
	readRemoteMemory(process, address, buffer.data(), buffer.size());

	disasm.EIP = (UIntPtr)buffer.data();
	disasm.VirtualAddr = start;

	while (true)
	{
		disasm.SecurityBlock = ((UIntPtr)buffer.data() + buffer.size()) - disasm.EIP;

		auto disamLength = Disasm(&disasm);
		if (disamLength == OUT_OF_BLOCK || disamLength == UNKNOWN_OPCODE)
		{
			break;
		}

		callbackDisassembledCode((LPVOID)disasm.VirtualAddr, disamLength, disasm.CompleteInstr);

		disasm.EIP += disamLength;
		if (disasm.EIP >= end)
		{
			break;
		}
		disasm.VirtualAddr += disamLength;
	}
}
<commit_msg>Fixed wrong section mapping.<commit_after>#define EXTERN_DLL_EXPORT

#include <windows.h>
#include <Psapi.h>
#include <tlhelp32.h>
#include <vector>
#include <algorithm>

#include <beaengine/BeaEngine.h>

const int PATH_MAXIMUM_LENGTH = 260;

enum class RequestFunction
{
	IsProcessValid,
	OpenRemoteProcess,
	CloseRemoteProcess,
	ReadRemoteMemory,
	WriteRemoteMemory,
	EnumerateProcesses,
	EnumerateRemoteSectionsAndModules
};

typedef LPVOID(__stdcall *RequestFunctionPtrCallback)(RequestFunction request);
RequestFunctionPtrCallback requestFunction;

EXTERN_DLL_EXPORT VOID __stdcall Initialize(RequestFunctionPtrCallback requestCallback)
{
	requestFunction = requestCallback;
}

DWORD lastError = 0;
EXTERN_DLL_EXPORT DWORD __stdcall GetLastErrorCode()
{
	return lastError;
}

EXTERN_DLL_EXPORT BOOL __stdcall IsProcessValid(HANDLE process)
{
	if (!process)
	{
		return FALSE;
	}

	auto retn = WaitForSingleObject(process, 0);
	if (retn == WAIT_FAILED)
	{
		return FALSE;
	}
	return retn == WAIT_TIMEOUT;
}

EXTERN_DLL_EXPORT LPVOID __stdcall OpenRemoteProcess(DWORD pid, DWORD desiredAccess)
{
	return OpenProcess(desiredAccess, FALSE, pid);
}

EXTERN_DLL_EXPORT VOID __stdcall CloseRemoteProcess(HANDLE process)
{
	CloseHandle(process);
}

EXTERN_DLL_EXPORT BOOL __stdcall ReadRemoteMemory(HANDLE process, LPCVOID address, LPVOID buffer, SIZE_T size)
{
	if (ReadProcessMemory(process, address, buffer, size, nullptr))
	{
		lastError = 0;

		return TRUE;
	}

	lastError = GetLastError();

	return FALSE;
}

EXTERN_DLL_EXPORT BOOL __stdcall WriteRemoteMemory(HANDLE process, LPVOID address, LPCVOID buffer, SIZE_T size)
{
	DWORD oldProtect;
	if (VirtualProtectEx(process, address, size, PAGE_EXECUTE_READWRITE, &oldProtect))
	{
		if (WriteProcessMemory(process, address, buffer, size, nullptr))
		{
			VirtualProtectEx(process, address, size, oldProtect, nullptr);

			lastError = 0;

			return TRUE;
		}
	}

	lastError = GetLastError();

	return FALSE;
}

enum class Platform
{
	Unknown,
	X86,
	X64
};

Platform GetProcessPlatform(HANDLE process)
{
	auto GetProcessorArchitecture = []()
	{
		static USHORT processorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
		if (processorArchitecture == PROCESSOR_ARCHITECTURE_UNKNOWN)
		{
			SYSTEM_INFO info = {};
			GetNativeSystemInfo(&info);

			processorArchitecture = info.wProcessorArchitecture;
		}
		return processorArchitecture;
	};

	switch (GetProcessorArchitecture())
	{
		case PROCESSOR_ARCHITECTURE_INTEL:
			return Platform::X86;
		case PROCESSOR_ARCHITECTURE_AMD64:
			BOOL isWow64 = FALSE;
			if (IsWow64Process(process, &isWow64))
			{
				return isWow64 ? Platform::X86 : Platform::X64;
			}

#ifdef _WIN64
			return Platform::X64;
#else
			return Platform::X86;
#endif
	}
	return Platform::Unknown;
}

typedef VOID(__stdcall EnumerateProcessCallback)(DWORD pid, WCHAR modulePath[PATH_MAXIMUM_LENGTH]);

EXTERN_DLL_EXPORT VOID __stdcall EnumerateProcesses(EnumerateProcessCallback callbackProcess)
{
	if (callbackProcess == nullptr)
	{
		return;
	}

	auto handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (handle != INVALID_HANDLE_VALUE)
	{
		PROCESSENTRY32W pe32 = {};
		pe32.dwSize = sizeof(PROCESSENTRY32W);
		if (Process32FirstW(handle, &pe32))
		{
			auto openRemoteProcess = reinterpret_cast<decltype(OpenRemoteProcess)*>(requestFunction(RequestFunction::OpenRemoteProcess));
			auto closeRemoteProcess = reinterpret_cast<decltype(CloseRemoteProcess)*>(requestFunction(RequestFunction::CloseRemoteProcess));

			do
			{
				auto process = openRemoteProcess(pe32.th32ProcessID, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ);
				if (process != nullptr && process != INVALID_HANDLE_VALUE)
				{
					auto platform = GetProcessPlatform(process);

#ifdef _WIN64
					if (platform == Platform::X64)
#else
					if (platform == Platform::X86)
#endif
					{
						WCHAR process_path[MAX_PATH] = { };
						GetModuleFileNameExW(process, NULL, process_path, MAX_PATH);

						callbackProcess(pe32.th32ProcessID, process_path);
					}

					closeRemoteProcess(process);
				}
			} while (Process32NextW(handle, &pe32));
		}

		CloseHandle(handle);

		lastError = 0;

		return;
	}

	lastError = GetLastError();
}

typedef VOID(__stdcall EnumerateRemoteSectionsCallback)(LPVOID baseAddress, SIZE_T regionSize, BYTE name[IMAGE_SIZEOF_SHORT_NAME + 2], DWORD state, DWORD protection, DWORD type, WCHAR modulePath[PATH_MAXIMUM_LENGTH]);
typedef VOID(__stdcall EnumerateRemoteModulesCallback)(LPVOID baseAddress, SIZE_T regionSize, WCHAR modulePath[PATH_MAXIMUM_LENGTH]);

EXTERN_DLL_EXPORT VOID __stdcall EnumerateRemoteSectionsAndModules(HANDLE process, EnumerateRemoteSectionsCallback callbackSection, EnumerateRemoteModulesCallback callbackModule)
{
	if (callbackSection == nullptr && callbackModule == nullptr)
	{
		return;
	}

	struct SectionInfo
	{
		LPVOID BaseAddress;
		SIZE_T RegionSize;
		BYTE Name[IMAGE_SIZEOF_SHORT_NAME + 2];
		DWORD State;
		DWORD Protection;
		DWORD Type;
		WCHAR ModulePath[PATH_MAXIMUM_LENGTH];
	};
	std::vector<SectionInfo> sections;

	SYSTEM_INFO sysInfo;
	GetSystemInfo(&sysInfo);

	MEMORY_BASIC_INFORMATION memInfo;
	size_t address = (size_t)sysInfo.lpMinimumApplicationAddress;
	while (address < (size_t)sysInfo.lpMaximumApplicationAddress)
	{
		if (VirtualQueryEx(process, (LPCVOID)address, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) != 0)
		{
			if (memInfo.State == MEM_COMMIT /*&& memInfo.Type == MEM_PRIVATE*/)
			{
				SectionInfo section = {};
				section.BaseAddress = memInfo.BaseAddress;
				section.RegionSize = memInfo.RegionSize;
				section.State = memInfo.State;
				section.Protection = memInfo.Protect;
				section.Type = memInfo.Type;

				sections.push_back(std::move(section));
			}
			address = (ULONG_PTR)memInfo.BaseAddress + memInfo.RegionSize;
		}
		else
		{
			address += 1024;
		}
	}

	auto handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(process));
	if (handle != INVALID_HANDLE_VALUE)
	{
		MODULEENTRY32W me32 = {};
		me32.dwSize = sizeof(MODULEENTRY32W);
		if (Module32FirstW(handle, &me32))
		{
			auto readRemoteMemory = reinterpret_cast<decltype(ReadRemoteMemory)*>(requestFunction(RequestFunction::ReadRemoteMemory));

			do
			{
				if (callbackModule != nullptr)
				{
					callbackModule(me32.modBaseAddr, me32.modBaseSize, me32.szExePath);
				}

				if (callbackSection != nullptr)
				{
					auto it = std::lower_bound(std::begin(sections), std::end(sections), (LPVOID)me32.modBaseAddr, [&sections](const SectionInfo& lhs, const LPVOID& rhs)
					{
						return lhs.BaseAddress < rhs;
					});

					IMAGE_DOS_HEADER DosHdr = {};
					IMAGE_NT_HEADERS NtHdr = {};

					readRemoteMemory(process, me32.modBaseAddr, &DosHdr, sizeof(IMAGE_DOS_HEADER));
					readRemoteMemory(process, me32.modBaseAddr + DosHdr.e_lfanew, &NtHdr, sizeof(IMAGE_NT_HEADERS));

					std::vector<IMAGE_SECTION_HEADER> sectionHeaders(NtHdr.FileHeader.NumberOfSections);
					readRemoteMemory(process, me32.modBaseAddr + DosHdr.e_lfanew + sizeof(IMAGE_NT_HEADERS), sectionHeaders.data(), NtHdr.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
					for (int i = 0; i < NtHdr.FileHeader.NumberOfSections; ++i)
					{
						auto&& section = sectionHeaders[i];

						auto sectionAddress = (size_t)me32.modBaseAddr + section.VirtualAddress;
						for (auto j = it; j != std::end(sections); ++j)
						{
							if (sectionAddress >= (size_t)j->BaseAddress && sectionAddress < (size_t)j->BaseAddress + (size_t)j->RegionSize)
							{
								std::memcpy(j->Name, section.Name, IMAGE_SIZEOF_SHORT_NAME);
								std::memcpy(j->ModulePath, me32.szExePath, sizeof(SectionInfo::ModulePath));
								break;
							}
						}

					}
				}
			} while (Module32NextW(handle, &me32));
		}

		CloseHandle(handle);

		if (callbackSection != nullptr)
		{
			for (auto&& section : sections)
			{
				callbackSection(section.BaseAddress, section.RegionSize, section.Name, section.State, section.Protection, section.Type, section.ModulePath);
			}
		}

		lastError = 0;

		return;
	}

	lastError = GetLastError();
}

typedef VOID(__stdcall DisassembleRemoteCodeCallback)(LPVOID address, DWORD length, CHAR instruction[64]);

EXTERN_DLL_EXPORT VOID __stdcall DisassembleRemoteCode(HANDLE process, LPVOID address, int length, DisassembleRemoteCodeCallback callbackDisassembledCode)
{
	if (callbackDisassembledCode == nullptr)
	{
		return;
	}

	UIntPtr start = (UIntPtr)address;
	UIntPtr end = start + length;
	if (end <= start)
	{
		return;
	}

	DISASM disasm;
	std::memset(&disasm, 0, sizeof(DISASM));
	disasm.Options = NasmSyntax + PrefixedNumeral;
#ifdef _WIN64
	disasm.Archi = 64;
#endif

	auto readRemoteMemory = reinterpret_cast<decltype(ReadRemoteMemory)*>(requestFunction(RequestFunction::ReadRemoteMemory));

	std::vector<uint8_t> buffer(length);
	readRemoteMemory(process, address, buffer.data(), buffer.size());

	disasm.EIP = (UIntPtr)buffer.data();
	disasm.VirtualAddr = start;

	while (true)
	{
		disasm.SecurityBlock = ((UIntPtr)buffer.data() + buffer.size()) - disasm.EIP;

		auto disamLength = Disasm(&disasm);
		if (disamLength == OUT_OF_BLOCK || disamLength == UNKNOWN_OPCODE)
		{
			break;
		}

		callbackDisassembledCode((LPVOID)disasm.VirtualAddr, disamLength, disasm.CompleteInstr);

		disasm.EIP += disamLength;
		if (disasm.EIP >= end)
		{
			break;
		}
		disasm.VirtualAddr += disamLength;
	}
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

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

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

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"

#include "OgreZip.h"

#include "OgreLogManager.h"
#include "OgreException.h"
#include "OgreStringVector.h"
#include "OgreRoot.h"

#include <zzip/zzip.h>

namespace Ogre {

    /// Utility method to format out zzip errors
    String getZzipErrorDescription(zzip_error_t zzipError)
    {
        String errorMsg;
        switch (zzipError)
        {
        case ZZIP_NO_ERROR:
            break;
        case ZZIP_OUTOFMEM:
            errorMsg = "Out of memory.";
            break;
        case ZZIP_DIR_OPEN:
        case ZZIP_DIR_STAT:
        case ZZIP_DIR_SEEK:
        case ZZIP_DIR_READ:
            errorMsg = "Unable to read zip file.";
            break;
        case ZZIP_UNSUPP_COMPR:
            errorMsg = "Unsupported compression format.";
            break;
        case ZZIP_CORRUPTED:
            errorMsg = "Corrupted archive.";
            break;
        default:
            errorMsg = "Unknown error.";
            break;
        };

        return errorMsg;
    }
    //-----------------------------------------------------------------------
    ZipArchive::ZipArchive(const String& name, const String& archType )
        : Archive(name, archType), mZzipDir(0)
    {
    }
    //-----------------------------------------------------------------------
    ZipArchive::~ZipArchive()
    {
        unload();
    }
    //-----------------------------------------------------------------------
    void ZipArchive::load()
    {
        if (!mZzipDir)
        {
            zzip_error_t zzipError;
            mZzipDir = zzip_dir_open(mName.c_str(), &zzipError);
            checkZzipError(zzipError, "opening archive");

            // Cache names
            ZZIP_DIRENT zzipEntry;
            while (zzip_dir_read(mZzipDir, &zzipEntry))
            {
                FileInfo info;
				info.archive = this;
                // Get basename / path
                StringUtil::splitFilename(zzipEntry.d_name, info.basename, info.path);
                info.filename = zzipEntry.d_name;
                // Get sizes
                info.compressedSize = static_cast<size_t>(zzipEntry.d_csize);
                info.uncompressedSize = static_cast<size_t>(zzipEntry.st_size);
                // folder entries
                if (info.basename.empty())
                {
                    info.filename = info.filename.substr (0, info.filename.length () - 1);
                    StringUtil::splitFilename(info.filename, info.basename, info.path);
                    // Set compressed size to -1 for folders; anyway nobody will check
                    // the compressed size of a folder, and if he does, its useless anyway
                    info.compressedSize = size_t (-1);
                }

                mFileList.push_back(info);

            }

        }
    }
    //-----------------------------------------------------------------------
    void ZipArchive::unload()
    {
        if (mZzipDir)
        {
            zzip_dir_close(mZzipDir);
            mZzipDir = 0;
            mFileList.clear();
        }

    }
    //-----------------------------------------------------------------------
	DataStreamPtr ZipArchive::open(const String& filename) const
    {

        // Format not used here (always binary)
        ZZIP_FILE* zzipFile =
            zzip_file_open(mZzipDir, filename.c_str(), ZZIP_ONLYZIP | ZZIP_CASELESS);
        if (!zzipFile)
		{
            int zerr = zzip_error(mZzipDir);
            String zzDesc = getZzipErrorDescription((zzip_error_t)zerr);
            LogManager::getSingleton().logMessage(
                mName + " - Unable to open file " + filename + ", error was '" + zzDesc + "'");

			// return null pointer
			return DataStreamPtr();
		}

		// Get uncompressed size too
		ZZIP_STAT zstat;
		zzip_dir_stat(mZzipDir, filename.c_str(), &zstat, ZZIP_CASEINSENSITIVE);

        // Construct & return stream
        return DataStreamPtr(OGRE_NEW ZipDataStream(filename, zzipFile, static_cast<size_t>(zstat.st_size)));

    }
    //-----------------------------------------------------------------------
    StringVectorPtr ZipArchive::list(bool recursive, bool dirs)
    {
        StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);

        FileInfoList::iterator i, iend;
        iend = mFileList.end();
        for (i = mFileList.begin(); i != iend; ++i)
            if ((dirs == (i->compressedSize == size_t (-1))) &&
                (recursive || i->path.empty()))
                ret->push_back(i->filename);

        return ret;
    }
    //-----------------------------------------------------------------------
    FileInfoListPtr ZipArchive::listFileInfo(bool recursive, bool dirs)
    {
        FileInfoList* fil = OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)();
        FileInfoList::const_iterator i, iend;
        iend = mFileList.end();
        for (i = mFileList.begin(); i != iend; ++i)
            if ((dirs == (i->compressedSize == size_t (-1))) &&
                (recursive || i->path.empty()))
                fil->push_back(*i);

        return FileInfoListPtr(fil, SPFM_DELETE_T);
    }
    //-----------------------------------------------------------------------
    StringVectorPtr ZipArchive::find(const String& pattern, bool recursive, bool dirs)
    {
        StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
        // If pattern contains a directory name, do a full match
        bool full_match = (pattern.find ('/') != String::npos) ||
                          (pattern.find ('\\') != String::npos);

        FileInfoList::iterator i, iend;
        iend = mFileList.end();
        for (i = mFileList.begin(); i != iend; ++i)
            if ((dirs == (i->compressedSize == size_t (-1))) &&
                (recursive || full_match || i->path.empty()))
                // Check basename matches pattern (zip is case insensitive)
                if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false))
                    ret->push_back(i->filename);

        return ret;
    }
    //-----------------------------------------------------------------------
	FileInfoListPtr ZipArchive::findFileInfo(const String& pattern,
        bool recursive, bool dirs)
    {
        FileInfoListPtr ret = FileInfoListPtr(OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
        // If pattern contains a directory name, do a full match
        bool full_match = (pattern.find ('/') != String::npos) ||
                          (pattern.find ('\\') != String::npos);

        FileInfoList::iterator i, iend;
        iend = mFileList.end();
        for (i = mFileList.begin(); i != iend; ++i)
            if ((dirs == (i->compressedSize == size_t (-1))) &&
                (recursive || full_match || i->path.empty()))
                // Check name matches pattern (zip is case insensitive)
                if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false))
                    ret->push_back(*i);

        return ret;
    }
    //-----------------------------------------------------------------------
	bool ZipArchive::exists(const String& filename)
	{
		ZZIP_STAT zstat;
		int res = zzip_dir_stat(mZzipDir, filename.c_str(), &zstat, ZZIP_CASEINSENSITIVE);

		return (res == ZZIP_NO_ERROR);

	}
	//-----------------------------------------------------------------------
    void ZipArchive::checkZzipError(int zzipError, const String& operation) const
    {
        if (zzipError != ZZIP_NO_ERROR)
        {
            String errorMsg = getZzipErrorDescription(static_cast<zzip_error_t>(zzipError));

            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                mName + " - error whilst " + operation + ": " + errorMsg,
                "ZipArchive::checkZzipError");
        }
    }
    //-----------------------------------------------------------------------
    //-----------------------------------------------------------------------
    //-----------------------------------------------------------------------
    ZipDataStream::ZipDataStream(ZZIP_FILE* zzipFile, size_t uncompressedSize)
        : mZzipFile(zzipFile)
    {
		mSize = uncompressedSize;
    }
    //-----------------------------------------------------------------------
    ZipDataStream::ZipDataStream(const String& name, ZZIP_FILE* zzipFile, size_t uncompressedSize)
        :DataStream(name), mZzipFile(zzipFile)
    {
		mSize = uncompressedSize;
    }
    //-----------------------------------------------------------------------
	ZipDataStream::~ZipDataStream()
	{
		close();
	}
    //-----------------------------------------------------------------------
    size_t ZipDataStream::read(void* buf, size_t count)
    {
        zzip_ssize_t r = zzip_file_read(mZzipFile, (char*)buf, count);
        if (r<0) {
            ZZIP_DIR *dir = zzip_dirhandle(mZzipFile);
            String msg = zzip_strerror_of(dir);
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                        mName+" - error from zziplib: "+msg,
                        "ZipDataStream::read");
        }
        return (size_t) r;
    }
    //-----------------------------------------------------------------------
    void ZipDataStream::skip(long count)
    {
        zzip_seek(mZzipFile, static_cast<zzip_off_t>(count), SEEK_CUR);
    }
    //-----------------------------------------------------------------------
    void ZipDataStream::seek( size_t pos )
    {
		zzip_seek(mZzipFile, static_cast<zzip_off_t>(pos), SEEK_SET);
    }
    //-----------------------------------------------------------------------
    size_t ZipDataStream::tell(void) const
    {
		return zzip_tell(mZzipFile);
    }
    //-----------------------------------------------------------------------
    bool ZipDataStream::eof(void) const
    {
        return (zzip_tell(mZzipFile) >= static_cast<zzip_off_t>(mSize));
    }
    //-----------------------------------------------------------------------
    void ZipDataStream::close(void)
    {
        zzip_file_close(mZzipFile);
    }
    //-----------------------------------------------------------------------
    const String& ZipArchiveFactory::getType(void) const
    {
        static String name = "Zip";
        return name;
    }

}
<commit_msg>Tolerate someone calling ZDataStream::close before destruction<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

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

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

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"

#include "OgreZip.h"

#include "OgreLogManager.h"
#include "OgreException.h"
#include "OgreStringVector.h"
#include "OgreRoot.h"

#include <zzip/zzip.h>

namespace Ogre {

    /// Utility method to format out zzip errors
    String getZzipErrorDescription(zzip_error_t zzipError)
    {
        String errorMsg;
        switch (zzipError)
        {
        case ZZIP_NO_ERROR:
            break;
        case ZZIP_OUTOFMEM:
            errorMsg = "Out of memory.";
            break;
        case ZZIP_DIR_OPEN:
        case ZZIP_DIR_STAT:
        case ZZIP_DIR_SEEK:
        case ZZIP_DIR_READ:
            errorMsg = "Unable to read zip file.";
            break;
        case ZZIP_UNSUPP_COMPR:
            errorMsg = "Unsupported compression format.";
            break;
        case ZZIP_CORRUPTED:
            errorMsg = "Corrupted archive.";
            break;
        default:
            errorMsg = "Unknown error.";
            break;
        };

        return errorMsg;
    }
    //-----------------------------------------------------------------------
    ZipArchive::ZipArchive(const String& name, const String& archType )
        : Archive(name, archType), mZzipDir(0)
    {
    }
    //-----------------------------------------------------------------------
    ZipArchive::~ZipArchive()
    {
        unload();
    }
    //-----------------------------------------------------------------------
    void ZipArchive::load()
    {
        if (!mZzipDir)
        {
            zzip_error_t zzipError;
            mZzipDir = zzip_dir_open(mName.c_str(), &zzipError);
            checkZzipError(zzipError, "opening archive");

            // Cache names
            ZZIP_DIRENT zzipEntry;
            while (zzip_dir_read(mZzipDir, &zzipEntry))
            {
                FileInfo info;
				info.archive = this;
                // Get basename / path
                StringUtil::splitFilename(zzipEntry.d_name, info.basename, info.path);
                info.filename = zzipEntry.d_name;
                // Get sizes
                info.compressedSize = static_cast<size_t>(zzipEntry.d_csize);
                info.uncompressedSize = static_cast<size_t>(zzipEntry.st_size);
                // folder entries
                if (info.basename.empty())
                {
                    info.filename = info.filename.substr (0, info.filename.length () - 1);
                    StringUtil::splitFilename(info.filename, info.basename, info.path);
                    // Set compressed size to -1 for folders; anyway nobody will check
                    // the compressed size of a folder, and if he does, its useless anyway
                    info.compressedSize = size_t (-1);
                }

                mFileList.push_back(info);

            }

        }
    }
    //-----------------------------------------------------------------------
    void ZipArchive::unload()
    {
        if (mZzipDir)
        {
            zzip_dir_close(mZzipDir);
            mZzipDir = 0;
            mFileList.clear();
        }

    }
    //-----------------------------------------------------------------------
	DataStreamPtr ZipArchive::open(const String& filename) const
    {

        // Format not used here (always binary)
        ZZIP_FILE* zzipFile =
            zzip_file_open(mZzipDir, filename.c_str(), ZZIP_ONLYZIP | ZZIP_CASELESS);
        if (!zzipFile)
		{
            int zerr = zzip_error(mZzipDir);
            String zzDesc = getZzipErrorDescription((zzip_error_t)zerr);
            LogManager::getSingleton().logMessage(
                mName + " - Unable to open file " + filename + ", error was '" + zzDesc + "'");

			// return null pointer
			return DataStreamPtr();
		}

		// Get uncompressed size too
		ZZIP_STAT zstat;
		zzip_dir_stat(mZzipDir, filename.c_str(), &zstat, ZZIP_CASEINSENSITIVE);

        // Construct & return stream
        return DataStreamPtr(OGRE_NEW ZipDataStream(filename, zzipFile, static_cast<size_t>(zstat.st_size)));

    }
    //-----------------------------------------------------------------------
    StringVectorPtr ZipArchive::list(bool recursive, bool dirs)
    {
        StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);

        FileInfoList::iterator i, iend;
        iend = mFileList.end();
        for (i = mFileList.begin(); i != iend; ++i)
            if ((dirs == (i->compressedSize == size_t (-1))) &&
                (recursive || i->path.empty()))
                ret->push_back(i->filename);

        return ret;
    }
    //-----------------------------------------------------------------------
    FileInfoListPtr ZipArchive::listFileInfo(bool recursive, bool dirs)
    {
        FileInfoList* fil = OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)();
        FileInfoList::const_iterator i, iend;
        iend = mFileList.end();
        for (i = mFileList.begin(); i != iend; ++i)
            if ((dirs == (i->compressedSize == size_t (-1))) &&
                (recursive || i->path.empty()))
                fil->push_back(*i);

        return FileInfoListPtr(fil, SPFM_DELETE_T);
    }
    //-----------------------------------------------------------------------
    StringVectorPtr ZipArchive::find(const String& pattern, bool recursive, bool dirs)
    {
        StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
        // If pattern contains a directory name, do a full match
        bool full_match = (pattern.find ('/') != String::npos) ||
                          (pattern.find ('\\') != String::npos);

        FileInfoList::iterator i, iend;
        iend = mFileList.end();
        for (i = mFileList.begin(); i != iend; ++i)
            if ((dirs == (i->compressedSize == size_t (-1))) &&
                (recursive || full_match || i->path.empty()))
                // Check basename matches pattern (zip is case insensitive)
                if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false))
                    ret->push_back(i->filename);

        return ret;
    }
    //-----------------------------------------------------------------------
	FileInfoListPtr ZipArchive::findFileInfo(const String& pattern,
        bool recursive, bool dirs)
    {
        FileInfoListPtr ret = FileInfoListPtr(OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
        // If pattern contains a directory name, do a full match
        bool full_match = (pattern.find ('/') != String::npos) ||
                          (pattern.find ('\\') != String::npos);

        FileInfoList::iterator i, iend;
        iend = mFileList.end();
        for (i = mFileList.begin(); i != iend; ++i)
            if ((dirs == (i->compressedSize == size_t (-1))) &&
                (recursive || full_match || i->path.empty()))
                // Check name matches pattern (zip is case insensitive)
                if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false))
                    ret->push_back(*i);

        return ret;
    }
    //-----------------------------------------------------------------------
	bool ZipArchive::exists(const String& filename)
	{
		ZZIP_STAT zstat;
		int res = zzip_dir_stat(mZzipDir, filename.c_str(), &zstat, ZZIP_CASEINSENSITIVE);

		return (res == ZZIP_NO_ERROR);

	}
	//-----------------------------------------------------------------------
    void ZipArchive::checkZzipError(int zzipError, const String& operation) const
    {
        if (zzipError != ZZIP_NO_ERROR)
        {
            String errorMsg = getZzipErrorDescription(static_cast<zzip_error_t>(zzipError));

            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                mName + " - error whilst " + operation + ": " + errorMsg,
                "ZipArchive::checkZzipError");
        }
    }
    //-----------------------------------------------------------------------
    //-----------------------------------------------------------------------
    //-----------------------------------------------------------------------
    ZipDataStream::ZipDataStream(ZZIP_FILE* zzipFile, size_t uncompressedSize)
        : mZzipFile(zzipFile)
    {
		mSize = uncompressedSize;
    }
    //-----------------------------------------------------------------------
    ZipDataStream::ZipDataStream(const String& name, ZZIP_FILE* zzipFile, size_t uncompressedSize)
        :DataStream(name), mZzipFile(zzipFile)
    {
		mSize = uncompressedSize;
    }
    //-----------------------------------------------------------------------
	ZipDataStream::~ZipDataStream()
	{
		close();
	}
    //-----------------------------------------------------------------------
    size_t ZipDataStream::read(void* buf, size_t count)
    {
        zzip_ssize_t r = zzip_file_read(mZzipFile, (char*)buf, count);
        if (r<0) {
            ZZIP_DIR *dir = zzip_dirhandle(mZzipFile);
            String msg = zzip_strerror_of(dir);
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                        mName+" - error from zziplib: "+msg,
                        "ZipDataStream::read");
        }
        return (size_t) r;
    }
    //-----------------------------------------------------------------------
    void ZipDataStream::skip(long count)
    {
        zzip_seek(mZzipFile, static_cast<zzip_off_t>(count), SEEK_CUR);
    }
    //-----------------------------------------------------------------------
    void ZipDataStream::seek( size_t pos )
    {
		zzip_seek(mZzipFile, static_cast<zzip_off_t>(pos), SEEK_SET);
    }
    //-----------------------------------------------------------------------
    size_t ZipDataStream::tell(void) const
    {
		return zzip_tell(mZzipFile);
    }
    //-----------------------------------------------------------------------
    bool ZipDataStream::eof(void) const
    {
        return (zzip_tell(mZzipFile) >= static_cast<zzip_off_t>(mSize));
    }
    //-----------------------------------------------------------------------
    void ZipDataStream::close(void)
    {
		// allow repeat calls
		if (mZzipFile)
		{
			zzip_file_close(mZzipFile);
			mZzipFile = 0;
		}
    }
    //-----------------------------------------------------------------------
    const String& ZipArchiveFactory::getType(void) const
    {
        static String name = "Zip";
        return name;
    }

}
<|endoftext|>


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

        Copyright (C) 2014 Rory Walsh

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with Csound; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
    02110-1301 USA
 */

#include "OpcodeBase.hpp"
#include <algorithm>
#include <cmath>
#include <dirent.h>
#include <iostream>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <vector>

using namespace std;
using namespace csound;

/* this function will load all samples of supported types into function
   tables number 'index' and upwards.
   It return the number of samples loaded */
int loadSamplesToTables(CSOUND *csound, int index, char *directory,
                        int skiptime, int format, int channel);

//-----------------------------------------------------------------
//      i-rate class
//-----------------------------------------------------------------
class iftsamplebank : public OpcodeBase<iftsamplebank> {
public:
  // Outputs.
  MYFLT *numberOfFiles;
  // Inputs.
  STRINGDAT *sDirectory;
  MYFLT *index;
  //    MYFLT* trigger;
  MYFLT *skiptime;
  MYFLT *format;
  MYFLT *channel;

  iftsamplebank() {
    channel = 0;
    index = 0;
    skiptime = 0;
    format = 0;
    index = 0;
    numberOfFiles = 0;
    sDirectory = NULL;
  }

  // init-pass
  int init(CSOUND *csound) {

    *numberOfFiles = loadSamplesToTables(
        csound, *index, (char *)sDirectory->data, *skiptime, *format, *channel);
    return OK;
  }

  int noteoff(CSOUND *) { return OK; }
};

//-----------------------------------------------------------------
//      k-rate class
//-----------------------------------------------------------------
class kftsamplebank : public OpcodeBase<kftsamplebank> {
public:
  // Outputs.
  MYFLT *numberOfFiles;
  // Inputs.
  STRINGDAT *sDirectory;
  MYFLT *index;
  MYFLT *trigger;
  MYFLT *skiptime;
  MYFLT *format;
  MYFLT *channel;
  int internalCounter;
  kftsamplebank() : internalCounter(0) {
    channel = 0;
    index = 0;
    skiptime = 0;
    format = 0;
    index = 0;
    trigger = 0;
  }

  // init-pass
  int init(CSOUND *csound) {
    IGN(csound);
    *numberOfFiles =
          loadSamplesToTables(csound, *index, (char *)sDirectory->data,
                              *skiptime, *format, *channel);
    *trigger = 0;
    return OK;
  }

  int noteoff(CSOUND *) { return OK; }

  int kontrol(CSOUND *csound) {
    // if directry changes update tables..
    if (*trigger == 1) {
      *numberOfFiles =
          loadSamplesToTables(csound, *index, (char *)sDirectory->data,
                              *skiptime, *format, *channel);
      *trigger = 0;
    }
    return OK;
  }
};

//-----------------------------------------------------------------
//      load samples into function tables
//-----------------------------------------------------------------
int loadSamplesToTables(CSOUND *csound, int index, char *directory,
                        int skiptime, int format, int channel) {

  if (directory) {
    DIR *dir = opendir(directory);
    std::vector<std::string> fileNames;
    std::vector<std::string> fileExtensions;
    int noOfFiles = 0;
    fileExtensions.push_back(".wav");
    fileExtensions.push_back(".aiff");
    fileExtensions.push_back(".ogg");
    fileExtensions.push_back(".flac");

    // check for valid path first
    if (dir) {
      struct dirent *ent;
      while ((ent = readdir(dir)) != NULL) {
        std::ostringstream fullFileName;
        // only use supported file types
        for (int i = 0; (size_t)i < fileExtensions.size(); i++)
        {
          std::string fname = ent->d_name;
          std::string extension;
          if(fname.find_last_of(".") != std::string::npos)
            extension = fname.substr(fname.find_last_of("."));

          if(extension == fileExtensions[i])
            {
              if (strlen(directory) > 0) {
#if defined(WIN32)
              fullFileName << directory << "\\" << ent->d_name;
#else
              fullFileName << directory << "/" << ent->d_name;
#endif
            }
            else
              fullFileName << ent->d_name;

            noOfFiles++;

            fileNames.push_back(fullFileName.str());
          }
        }
      }

      // Sort names
      std::sort(fileNames.begin(), fileNames.end());

      // push statements to score, starting with table number 'index'
      for (int y = 0; (size_t)y < fileNames.size(); y++) {
        std::ostringstream statement;
        statement << "f" << index + y << " 0 0 1 \"" << fileNames[y] << "\" "
                  << skiptime << " " << format << " " << channel << "\n";
        // csound->MessageS(csound, CSOUNDMSG_ORCH, statement.str().c_str());
        csound->InputMessage(csound, statement.str().c_str());
      }

      closedir(dir);
    } else {
      csound->Message(csound,
                      Str("Cannot load file. Error opening directory: %s\n"),
                      directory);
    }

    // return number of files
    return noOfFiles;
  } else
    return 0;
}

typedef struct {
  OPDS h;
  ARRAYDAT *outArr;
  STRINGDAT *directoryName;
  MYFLT *extension;
} DIR_STRUCT;

/* this function will looks for files of a set type, in a particular directory
 */
std::vector<std::string> searchDir(CSOUND *csound, char *directory,
                                   char *extension);

#include "arrays.h"
#if 0
/* from Opcodes/arrays.c */
static inline void tabensure(CSOUND *csound, ARRAYDAT *p, int size) {
    if (p->data==NULL || p->dimensions == 0 ||
        (p->dimensions==1 && p->sizes[0] < size)) {
      size_t ss;
      if (p->data == NULL) {
        CS_VARIABLE* var = p->arrayType->createVariable(csound, NULL);
        p->arrayMemberSize = var->memBlockSize;
      }
      ss = p->arrayMemberSize*size;
      if (p->data==NULL) {
        p->data = (MYFLT*)csound->Calloc(csound, ss);
        p->allocated = ss;
      }
      else if (ss > p->allocated) {
        p->data = (MYFLT*) csound->ReAlloc(csound, p->data, ss);
        p->allocated = ss;
      }
      if (p->dimensions==0) {
        p->dimensions = 1;
        p->sizes = (int32_t*)csound->Malloc(csound, sizeof(int32_t));
      }
    }
    p->sizes[0] = size;
}
#endif

static int directory(CSOUND *csound, DIR_STRUCT *p) {
  int inArgCount = p->INOCOUNT;
  char *extension, *file;
  std::vector<std::string> fileNames;

  if (inArgCount == 0)
    return csound->InitError(
        csound, "%s", Str("Error: you must pass a directory as a string."));

  if (inArgCount == 1) {
    fileNames = searchDir(csound, p->directoryName->data, (char *)"");
  }

  else if (inArgCount == 2) {
    CS_TYPE *argType = csound->GetTypeForArg(p->extension);
    if (strcmp("S", argType->varTypeName) == 0) {
      extension = csound->Strdup(csound, ((STRINGDAT *)p->extension)->data);
      fileNames = searchDir(csound, p->directoryName->data, extension);
    } else
      return csound->InitError(csound,
                               "%s", Str("Error: second parameter to directory"
                                   " must be a string"));
  }

  int numberOfFiles = fileNames.size();
  tabinit(csound, p->outArr, numberOfFiles);
  STRINGDAT *strings = (STRINGDAT *)p->outArr->data;

  for (int i = 0; i < numberOfFiles; i++) {
    file = &fileNames[i][0u];
    strings[i].size = strlen(file) + 1;
    strings[i].data = csound->Strdup(csound, file);
  }

  fileNames.clear();

  return OK;
}

//-----------------------------------------------------------------
//      load samples into function tables
//-----------------------------------------------------------------
std::vector<std::string> searchDir(CSOUND *csound, char *directory,
                                   char *extension) {
  std::vector<std::string> fileNames;
  if (directory) {
    DIR *dir = opendir(directory);
    std::string fileExtension(extension);
    int noOfFiles = 0;

    // check for valid path first
    if (dir) {
      struct dirent *ent;
      while ((ent = readdir(dir)) != NULL) {
        std::ostringstream fullFileName;

        std::string fname = ent->d_name;
        size_t lastPos = fname.find_last_of(".");
        if (fname.length() > 0 && (fileExtension.empty() ||
            (lastPos != std::string::npos &&
            fname.substr(lastPos) == fileExtension))) {
          if (strlen(directory) > 0) {
#if defined(WIN32)
            fullFileName << directory << "\\" << ent->d_name;
#else
            fullFileName << directory << "/" << ent->d_name;
#endif
          } else
            fullFileName << ent->d_name;

          noOfFiles++;
          fileNames.push_back(fullFileName.str());
        }
      }

      // Sort names
      std::sort(fileNames.begin(), fileNames.end());
    } else {
      csound->Message(csound, Str("Cannot find directory. "
                                  "Error opening directory: %s\n"),
                      directory);
    }
    closedir(dir);
  }

  return fileNames;
}

extern "C" {

PUBLIC int csoundModuleInit_ftsamplebank(CSOUND *csound) {

  int status = csound->AppendOpcode(
      csound, (char *)"ftsamplebank.k", sizeof(kftsamplebank), 0, 3,
      (char *)"k", (char *)"Skkkkk",
      (int (*)(CSOUND *, void *))kftsamplebank::init_,
      (int (*)(CSOUND *, void *))kftsamplebank::kontrol_,
      (int (*)(CSOUND *, void *))0);

  status |= csound->AppendOpcode(
      csound, (char *)"ftsamplebank.i", sizeof(iftsamplebank), 0, 1,
      (char *)"i", (char *)"Siiii",
      (int (*)(CSOUND *, void *))iftsamplebank::init_,
      (int (*)(CSOUND *, void *))0, (int (*)(CSOUND *, void *))0);

  /*  status |= csound->AppendOpcode(csound,
      (char*)"ftsamplebank",
      0xffff,
      0,
      0,
      0,
      0,
      0,
      0,
      0); */

  status |= csound->AppendOpcode(
      csound, (char *)"directory", sizeof(DIR_STRUCT), 0, 1, (char *)"S[]",
      (char *)"SN", (int (*)(CSOUND *, void *))directory,
      (int (*)(CSOUND *, void *))0, (int (*)(CSOUND *, void *))0);
  return status;
}

#ifndef INIT_STATIC_MODULES
PUBLIC int csoundModuleCreate(CSOUND *csound) {
  IGN(csound);
  return 0;
}

PUBLIC int csoundModuleInit(CSOUND *csound) {
  return csoundModuleInit_ftsamplebank(csound);
}

PUBLIC int csoundModuleDestroy(CSOUND *csound) {
  IGN(csound);
  return 0;
}
#endif
}
<commit_msg>Update ftsamplebank.cpp<commit_after>/*
    This file is part of Csound.

        Copyright (C) 2014 Rory Walsh

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with Csound; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
    02110-1301 USA
 */

#include <algorithm>
#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "OpcodeBase.hpp"
#include <dirent.h>
#include <sys/types.h>

using namespace std;
using namespace csound;

/* this function will load all samples of supported types into function
   tables number 'index' and upwards.
   It return the number of samples loaded */
int loadSamplesToTables(CSOUND *csound, int index, char *directory,
                        int skiptime, int format, int channel);

//-----------------------------------------------------------------
//      i-rate class
//-----------------------------------------------------------------
class iftsamplebank : public OpcodeBase<iftsamplebank> {
public:
  // Outputs.
  MYFLT *numberOfFiles;
  // Inputs.
  STRINGDAT *sDirectory;
  MYFLT *index;
  //    MYFLT* trigger;
  MYFLT *skiptime;
  MYFLT *format;
  MYFLT *channel;

  iftsamplebank() {
    channel = 0;
    index = 0;
    skiptime = 0;
    format = 0;
    index = 0;
    numberOfFiles = 0;
    sDirectory = NULL;
  }

  // init-pass
  int init(CSOUND *csound) {

    *numberOfFiles = loadSamplesToTables(
        csound, *index, (char *)sDirectory->data, *skiptime, *format, *channel);
    return OK;
  }

  int noteoff(CSOUND *) { return OK; }
};

//-----------------------------------------------------------------
//      k-rate class
//-----------------------------------------------------------------
class kftsamplebank : public OpcodeBase<kftsamplebank> {
public:
  // Outputs.
  MYFLT *numberOfFiles;
  // Inputs.
  STRINGDAT *sDirectory;
  MYFLT *index;
  MYFLT *trigger;
  MYFLT *skiptime;
  MYFLT *format;
  MYFLT *channel;
  int internalCounter;
  kftsamplebank() : internalCounter(0) {
    channel = 0;
    index = 0;
    skiptime = 0;
    format = 0;
    index = 0;
    trigger = 0;
  }

  // init-pass
  int init(CSOUND *csound) {
    IGN(csound);
    *numberOfFiles =
          loadSamplesToTables(csound, *index, (char *)sDirectory->data,
                              *skiptime, *format, *channel);
    *trigger = 0;
    return OK;
  }

  int noteoff(CSOUND *) { return OK; }

  int kontrol(CSOUND *csound) {
    // if directry changes update tables..
    if (*trigger == 1) {
      *numberOfFiles =
          loadSamplesToTables(csound, *index, (char *)sDirectory->data,
                              *skiptime, *format, *channel);
      *trigger = 0;
    }
    return OK;
  }
};

//-----------------------------------------------------------------
//      load samples into function tables
//-----------------------------------------------------------------
int loadSamplesToTables(CSOUND *csound, int index, char *directory,
                        int skiptime, int format, int channel) {

  if (directory) {
    DIR *dir = opendir(directory);
    std::vector<std::string> fileNames;
    std::vector<std::string> fileExtensions;
    int noOfFiles = 0;
    fileExtensions.push_back(".wav");
    fileExtensions.push_back(".aiff");
    fileExtensions.push_back(".ogg");
    fileExtensions.push_back(".flac");

    // check for valid path first
    if (dir) {
      struct dirent *ent;
      while ((ent = readdir(dir)) != NULL) {
        std::ostringstream fullFileName;
        // only use supported file types
        for (int i = 0; (size_t)i < fileExtensions.size(); i++)
        {
          std::string fname = ent->d_name;
          std::string extension;
          if(fname.find_last_of(".") != std::string::npos)
            extension = fname.substr(fname.find_last_of("."));

          if(extension == fileExtensions[i])
            {
              if (strlen(directory) > 0) {
#if defined(WIN32)
              fullFileName << directory << "\\" << ent->d_name;
#else
              fullFileName << directory << "/" << ent->d_name;
#endif
            }
            else
              fullFileName << ent->d_name;

            noOfFiles++;

            fileNames.push_back(fullFileName.str());
          }
        }
      }

      // Sort names
      std::sort(fileNames.begin(), fileNames.end());

      // push statements to score, starting with table number 'index'
      for (int y = 0; (size_t)y < fileNames.size(); y++) {
        std::ostringstream statement;
        statement << "f" << index + y << " 0 0 1 \"" << fileNames[y] << "\" "
                  << skiptime << " " << format << " " << channel << "\n";
        // csound->MessageS(csound, CSOUNDMSG_ORCH, statement.str().c_str());
        csound->InputMessage(csound, statement.str().c_str());
      }

      closedir(dir);
    } else {
      csound->Message(csound,
                      Str("Cannot load file. Error opening directory: %s\n"),
                      directory);
    }

    // return number of files
    return noOfFiles;
  } else
    return 0;
}

typedef struct {
  OPDS h;
  ARRAYDAT *outArr;
  STRINGDAT *directoryName;
  MYFLT *extension;
} DIR_STRUCT;

/* this function will looks for files of a set type, in a particular directory
 */
std::vector<std::string> searchDir(CSOUND *csound, char *directory,
                                   char *extension);

#include "arrays.h"
#if 0
/* from Opcodes/arrays.c */
static inline void tabensure(CSOUND *csound, ARRAYDAT *p, int size) {
    if (p->data==NULL || p->dimensions == 0 ||
        (p->dimensions==1 && p->sizes[0] < size)) {
      size_t ss;
      if (p->data == NULL) {
        CS_VARIABLE* var = p->arrayType->createVariable(csound, NULL);
        p->arrayMemberSize = var->memBlockSize;
      }
      ss = p->arrayMemberSize*size;
      if (p->data==NULL) {
        p->data = (MYFLT*)csound->Calloc(csound, ss);
        p->allocated = ss;
      }
      else if (ss > p->allocated) {
        p->data = (MYFLT*) csound->ReAlloc(csound, p->data, ss);
        p->allocated = ss;
      }
      if (p->dimensions==0) {
        p->dimensions = 1;
        p->sizes = (int32_t*)csound->Malloc(csound, sizeof(int32_t));
      }
    }
    p->sizes[0] = size;
}
#endif

static int directory(CSOUND *csound, DIR_STRUCT *p) {
  int inArgCount = p->INOCOUNT;
  char *extension, *file;
  std::vector<std::string> fileNames;

  if (inArgCount == 0)
    return csound->InitError(
        csound, "%s", Str("Error: you must pass a directory as a string."));

  if (inArgCount == 1) {
    fileNames = searchDir(csound, p->directoryName->data, (char *)"");
  }

  else if (inArgCount == 2) {
    CS_TYPE *argType = csound->GetTypeForArg(p->extension);
    if (strcmp("S", argType->varTypeName) == 0) {
      extension = csound->Strdup(csound, ((STRINGDAT *)p->extension)->data);
      fileNames = searchDir(csound, p->directoryName->data, extension);
    } else
      return csound->InitError(csound,
                               "%s", Str("Error: second parameter to directory"
                                   " must be a string"));
  }

  int numberOfFiles = fileNames.size();
  tabinit(csound, p->outArr, numberOfFiles);
  STRINGDAT *strings = (STRINGDAT *)p->outArr->data;

  for (int i = 0; i < numberOfFiles; i++) {
    file = &fileNames[i][0u];
    strings[i].size = strlen(file) + 1;
    strings[i].data = csound->Strdup(csound, file);
  }

  fileNames.clear();

  return OK;
}

//-----------------------------------------------------------------
//      load samples into function tables
//-----------------------------------------------------------------
std::vector<std::string> searchDir(CSOUND *csound, char *directory,
                                   char *extension) {
  std::vector<std::string> fileNames;
  if (directory) {
    DIR *dir = opendir(directory);
    std::string fileExtension(extension);
    int noOfFiles = 0;

    // check for valid path first
    if (dir) {
      struct dirent *ent;
      while ((ent = readdir(dir)) != NULL) {
        std::ostringstream fullFileName;

        std::string fname = ent->d_name;
        size_t lastPos = fname.find_last_of(".");
        if (fname.length() > 0 && (fileExtension.empty() ||
            (lastPos != std::string::npos &&
            fname.substr(lastPos) == fileExtension))) {
          if (strlen(directory) > 0) {
#if defined(WIN32)
            fullFileName << directory << "\\" << ent->d_name;
#else
            fullFileName << directory << "/" << ent->d_name;
#endif
          } else
            fullFileName << ent->d_name;

          noOfFiles++;
          fileNames.push_back(fullFileName.str());
        }
      }

      // Sort names
      std::sort(fileNames.begin(), fileNames.end());
    } else {
      csound->Message(csound, Str("Cannot find directory. "
                                  "Error opening directory: %s\n"),
                      directory);
    }
    closedir(dir);
  }

  return fileNames;
}

extern "C" {

PUBLIC int csoundModuleInit_ftsamplebank(CSOUND *csound) {

  int status = csound->AppendOpcode(
      csound, (char *)"ftsamplebank.k", sizeof(kftsamplebank), 0, 3,
      (char *)"k", (char *)"Skkkkk",
      (int (*)(CSOUND *, void *))kftsamplebank::init_,
      (int (*)(CSOUND *, void *))kftsamplebank::kontrol_,
      (int (*)(CSOUND *, void *))0);

  status |= csound->AppendOpcode(
      csound, (char *)"ftsamplebank.i", sizeof(iftsamplebank), 0, 1,
      (char *)"i", (char *)"Siiii",
      (int (*)(CSOUND *, void *))iftsamplebank::init_,
      (int (*)(CSOUND *, void *))0, (int (*)(CSOUND *, void *))0);

  /*  status |= csound->AppendOpcode(csound,
      (char*)"ftsamplebank",
      0xffff,
      0,
      0,
      0,
      0,
      0,
      0,
      0); */

  status |= csound->AppendOpcode(
      csound, (char *)"directory", sizeof(DIR_STRUCT), 0, 1, (char *)"S[]",
      (char *)"SN", (int (*)(CSOUND *, void *))directory,
      (int (*)(CSOUND *, void *))0, (int (*)(CSOUND *, void *))0);
  return status;
}

#ifndef INIT_STATIC_MODULES
PUBLIC int csoundModuleCreate(CSOUND *csound) {
  IGN(csound);
  return 0;
}

PUBLIC int csoundModuleInit(CSOUND *csound) {
  return csoundModuleInit_ftsamplebank(csound);
}

PUBLIC int csoundModuleDestroy(CSOUND *csound) {
  IGN(csound);
  return 0;
}
#endif
}
<|endoftext|>


<commit_before>// Copyright Hugh Perkins 2016

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "shims.h"

#include <iostream>

// using namespace cocl;
// using namespace std;

namespace cocl {

Shims::Shims() {
    _shimClByName["__shfl_down_3"] = R"(
inline float __shfl_down_3(local int *scratch, float v0, int v1, int v2) {
    // local float mem[1024];
    local float *mem = (local float *)scratch;
    int tid = get_local_id(0);
    int warpid = tid % 32;
    int warpstart = tid - warpid;
    mem[tid] = v0;
    //barrier(CLK_LOCAL_MEM_FENCE);
    int warpsrc = warpid + v1;
    warpsrc = warpsrc >= 32 ? warpid : warpsrc;
    return mem[warpstart + warpsrc];
}
)";

    _shimClByName["__shfl_down_2"] = R"(
inline float __shfl_down_2(local int *scratch, float v0, int v1) {
    return __shfl_down_3(scratch, v0, v1, 32);
}
)";
    _dependenciesByName["__shfl_down_2"].insert("__shfl_down_3");

    // note to self: just realized, umulhi is actually available in opencl 1.2 :-)
    // so, we should migrate this to use that, probably
    _shimClByName["__umulhi"] = R"(
inline unsigned int __umulhi(unsigned int v0, unsigned int v1) {
    unsigned long res = (unsigned long)v0 * v1;
    unsigned int res2 = res >> 32;
    return res2;
}
)";

// this code is from http://suhorukov.blogspot.co.uk/2011/12/opencl-11-atomic-operations-on-floating.html
    _shimClByName["__atomic_add_float"] = R"(
inline float __atomic_add_float(volatile __global float *source, const float operand) {
    union {
        unsigned int intVal;
        float floatVal;
    } newVal;
    union {
        unsigned int intVal;
        float floatVal;
    } prevVal;
    do {
        prevVal.floatVal = *source;
        newVal.floatVal = prevVal.floatVal + operand;
    } while (atomic_cmpxchg((volatile __global unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);
    return prevVal.floatVal;
}
)";

    _shimClByName["__atomic_inc_uint"] = R"(
inline unsigned int __atomic_inc_uint(volatile __global int *data, const unsigned int old) {
    unsigned int prevVal;
    unsigned int newVal;
    while(true) {
        prevVal = *data;
        newVal = prevVal >= old ? 0 : prevVal + 1;
        unsigned int res = atomic_cmpxchg((volatile __global unsigned int *)data, prevVal, newVal);
        if(res == prevVal) {
            break;
        }
    }
    return prevVal;
}
)";
}

void Shims::use(std::string name) {
    if(_shimClByName.find(name) == _shimClByName.end()) {
        std::cout << "shim " << name << " does not exist.  This is a bug in Coriander" << std::endl;
        throw std::runtime_error("shim " + name + " does not exist. This is a bug in Coriander");
    }
    shimsToBeUsed.insert(name);
    if(_dependenciesByName.find(name) != _dependenciesByName.end()) {
        const std::set<std::string> &deps = _dependenciesByName[name];
        for(auto it=deps.begin(); it != deps.end(); it++) {
            shimsToBeUsed.insert(*it);
        }
    }
}

void Shims::writeCl(std::ostream &os) {
    std::set<std::string> written;
    int attempts = 0;
    while(written.size() < shimsToBeUsed.size() && attempts < 10) {
        for(auto it=shimsToBeUsed.begin(); it != shimsToBeUsed.end(); it++) {
            std::string shimName = *it;
            std::cout << "write check " << shimName << std::endl;
            if(written.find(shimName) != written.end()) {
                continue;
            }
            bool writtenDependencies = true;
            // check written dependencies
            const std::set<std::string> &deps = _dependenciesByName[shimName];
            for(auto childit=deps.begin(); childit != deps.end(); childit++) {
                std::string childName = *childit;
                if(written.find(childName) == written.end()) {
                    std::cout << "  missing dep " << childName << std::endl;
                    writtenDependencies = false;
                    break;
                }
            }
            if(writtenDependencies) {
                os << _shimClByName[shimName];
                written.insert(shimName);
            }
        }
        attempts++;
    }
    if(written.size() < shimsToBeUsed.size()) {
        for(auto it=written.begin(); it != written.end(); it++) {
            std::cout << "wrote " << *it << " ok" << std::endl;
        }
        std::cout << std::endl;
        std::cout << "ERROR: Failed to write shims. This is a Coriander bug. Please log at https://github.com/hughperkins/coriander/issues" << std::endl;
        std::cout << std::endl;
        throw std::runtime_error("Failed to write shims");
    }
}

void Shims::copyFrom(const Shims &source) {
    for(auto it=source.shimsToBeUsed.begin(); it != source.shimsToBeUsed.end(); it++) {
        // shimsToBeUsed.insert(*it);
    }
    shimsToBeUsed.insert(source.shimsToBeUsed.begin(), source.shimsToBeUsed.end());
}

bool Shims::isUsed(std::string name) {
    return shimsToBeUsed.find(name) != shimsToBeUsed.end();
}

// std::string Shims::getClByName(std::string name) {
//     return _shimClByName[name];
// }

// std::set<std::string> Shims::getDependenciesByName(std::string name) {
//     return _dependenciesByName[name];
// }

} // namespace cocl
<commit_msg>reduce spam a bit<commit_after>// Copyright Hugh Perkins 2016

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "shims.h"

#include <iostream>

// using namespace cocl;
// using namespace std;

namespace cocl {

Shims::Shims() {
    _shimClByName["__shfl_down_3"] = R"(
inline float __shfl_down_3(local int *scratch, float v0, int v1, int v2) {
    // local float mem[1024];
    local float *mem = (local float *)scratch;
    int tid = get_local_id(0);
    int warpid = tid % 32;
    int warpstart = tid - warpid;
    mem[tid] = v0;
    //barrier(CLK_LOCAL_MEM_FENCE);
    int warpsrc = warpid + v1;
    warpsrc = warpsrc >= 32 ? warpid : warpsrc;
    return mem[warpstart + warpsrc];
}
)";

    _shimClByName["__shfl_down_2"] = R"(
inline float __shfl_down_2(local int *scratch, float v0, int v1) {
    return __shfl_down_3(scratch, v0, v1, 32);
}
)";
    _dependenciesByName["__shfl_down_2"].insert("__shfl_down_3");

    // note to self: just realized, umulhi is actually available in opencl 1.2 :-)
    // so, we should migrate this to use that, probably
    _shimClByName["__umulhi"] = R"(
inline unsigned int __umulhi(unsigned int v0, unsigned int v1) {
    unsigned long res = (unsigned long)v0 * v1;
    unsigned int res2 = res >> 32;
    return res2;
}
)";

// this code is from http://suhorukov.blogspot.co.uk/2011/12/opencl-11-atomic-operations-on-floating.html
    _shimClByName["__atomic_add_float"] = R"(
inline float __atomic_add_float(volatile __global float *source, const float operand) {
    union {
        unsigned int intVal;
        float floatVal;
    } newVal;
    union {
        unsigned int intVal;
        float floatVal;
    } prevVal;
    do {
        prevVal.floatVal = *source;
        newVal.floatVal = prevVal.floatVal + operand;
    } while (atomic_cmpxchg((volatile __global unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);
    return prevVal.floatVal;
}
)";

    _shimClByName["__atomic_inc_uint"] = R"(
inline unsigned int __atomic_inc_uint(volatile __global int *data, const unsigned int old) {
    unsigned int prevVal;
    unsigned int newVal;
    while(true) {
        prevVal = *data;
        newVal = prevVal >= old ? 0 : prevVal + 1;
        unsigned int res = atomic_cmpxchg((volatile __global unsigned int *)data, prevVal, newVal);
        if(res == prevVal) {
            break;
        }
    }
    return prevVal;
}
)";
}

void Shims::use(std::string name) {
    if(_shimClByName.find(name) == _shimClByName.end()) {
        std::cout << "shim " << name << " does not exist.  This is a bug in Coriander" << std::endl;
        throw std::runtime_error("shim " + name + " does not exist. This is a bug in Coriander");
    }
    shimsToBeUsed.insert(name);
    if(_dependenciesByName.find(name) != _dependenciesByName.end()) {
        const std::set<std::string> &deps = _dependenciesByName[name];
        for(auto it=deps.begin(); it != deps.end(); it++) {
            shimsToBeUsed.insert(*it);
        }
    }
}

void Shims::writeCl(std::ostream &os) {
    std::set<std::string> written;
    int attempts = 0;
    while(written.size() < shimsToBeUsed.size() && attempts < 10) {
        for(auto it=shimsToBeUsed.begin(); it != shimsToBeUsed.end(); it++) {
            std::string shimName = *it;
            if(written.find(shimName) != written.end()) {
                continue;
            }
            bool writtenDependencies = true;
            // check written dependencies
            const std::set<std::string> &deps = _dependenciesByName[shimName];
            for(auto childit=deps.begin(); childit != deps.end(); childit++) {
                std::string childName = *childit;
                if(written.find(childName) == written.end()) {
                    writtenDependencies = false;
                    break;
                }
            }
            if(writtenDependencies) {
                os << _shimClByName[shimName];
                written.insert(shimName);
            }
        }
        attempts++;
    }
    if(written.size() < shimsToBeUsed.size()) {
        for(auto it=written.begin(); it != written.end(); it++) {
            std::cout << "wrote " << *it << " ok" << std::endl;
        }
        std::cout << std::endl;
        std::cout << "ERROR: Failed to write shims. This is a Coriander bug. Please log at https://github.com/hughperkins/coriander/issues" << std::endl;
        std::cout << std::endl;
        throw std::runtime_error("Failed to write shims");
    }
}

void Shims::copyFrom(const Shims &source) {
    for(auto it=source.shimsToBeUsed.begin(); it != source.shimsToBeUsed.end(); it++) {
        // shimsToBeUsed.insert(*it);
    }
    shimsToBeUsed.insert(source.shimsToBeUsed.begin(), source.shimsToBeUsed.end());
}

bool Shims::isUsed(std::string name) {
    return shimsToBeUsed.find(name) != shimsToBeUsed.end();
}

// std::string Shims::getClByName(std::string name) {
//     return _shimClByName[name];
// }

// std::set<std::string> Shims::getDependenciesByName(std::string name) {
//     return _dependenciesByName[name];
// }

} // namespace cocl
<|endoftext|>


<commit_before>#include "easylogging++.h"
#include "json.hpp"
#include "snake.h"

using nlohmann::json;

// Good runs:   http://game.snake.cygni.se/#/viewgame/88a759cf-e406-4941-9eba-28d51ed9c600
//              http://game.snake.cygni.se/#/viewgame/af42c3a4-fbf9-4a14-b892-3fdf6da063a4
//              http://game.snake.cygni.se/#/viewgame/ed59e861-8147-4845-8f6c-3b586b2b91a4

// Postionen ges av int position => endast ett värde på mappen

// ---------------------- NEXT MOOVE  -------------------------------

std::string Snake::get_next_move(json map) {
  int mapHight = map["height"] ;
  int mapWidth = map["width"] ;

  //int response = 1;
  std::string responsArray [] = {"UP", "DOWN", "RIGHT", "LEFT"};

   std::array<double,4> responsValue;

  // Reset responsValue
  responsValue[0] = 0; // UP
  responsValue[1] = 0; // DOWN
  responsValue[2] = 0; // RIGHT
  responsValue[3] = 0; // LEFT

  // Hitta vår snake första gången vi spelar
  if(mySnakeSlot == -1){
  mySnakeSlot = 0;
      while(map["snakeInfos"][mySnakeSlot]["name"] != name){
        mySnakeSlot++;
      }
  }

  int snake_x, snake_y;
  std::tie(snake_x,snake_y) = pos2xy(map["snakeInfos"][mySnakeSlot]["positions"][0], map["width"]);
  // LOG(INFO) << "Snake pos: " << x << ", " << y ;
  //

  double danger[] = {0.0, 0.0, 0.0, 0.0};
  double food[] = {0.0, 0.0, 0.0, 0.0};
  int view_distance = 2;

  for (int i = 0; i < map["obstaclePositions"].size(); ++i) // OBSTACLE
  {
    int i_x, i_y;
    std::tie(i_x,i_y) = pos2xy(map["obstaclePositions"][i], map["width"]);
    int dist_x = i_x - snake_x;
    int dist_y = i_y - snake_y;

    if (dist_y > -view_distance && dist_y < 0 && abs(dist_x) < view_distance) // danger up
    {
      danger[0] += (view_distance + dist_y)*(view_distance + dist_y);
    }
    else if (dist_y > 0 && dist_y < view_distance  && abs(dist_x) < view_distance) //  danger down
    {
      danger[1] += (view_distance - dist_y)*(view_distance - dist_y);
    }

    if (dist_x > -view_distance && dist_x < 0  && abs(dist_y) < view_distance)
    {
      danger[3] += (view_distance + dist_x)*(view_distance + dist_x);
    }
    else if (dist_x > 0 && dist_x < view_distance  && abs(dist_y) < view_distance)
    {
      danger[2] += (view_distance - dist_y)*(view_distance - dist_y);
    }

  }

  for (int i = 0; i < map["foodPositions"].size(); ++i) // FOOD
  {
    int i_x, i_y;
    std::tie(i_x,i_y) = pos2xy(map["foodPositions"][i], map["width"]);
    int dist_x = i_x - snake_x;
    int dist_y = i_y - snake_y;

    if (dist_y > -view_distance && dist_y < 0 && abs(dist_x) < view_distance)
    {
      food[0] += (view_distance + dist_y)*(view_distance + dist_y);
    }
    else if (dist_y > 0 && dist_y < view_distance  && abs(dist_x) < view_distance)
    {
      food[1] += (view_distance - dist_y)*(view_distance - dist_y);
    }

    if (dist_x > -view_distance && dist_x < 0  && abs(dist_y) < view_distance)
    {
      food[3] += (view_distance + dist_x)*(view_distance + dist_x);
    }
    else if (dist_x > 0 && dist_x < view_distance  && abs(dist_y) < view_distance)
    {
      food[2] += (view_distance - dist_y)*(view_distance - dist_y);
    }
  }

  for (int j = 0; j < map["snakeInfos"].size(); ++j) // SNAKES (including yourself)
  {
    for (int i = 0; i < map["snakeInfos"][j]["positions"].size(); ++i)
    {
      int i_x, i_y;
      std::tie(i_x,i_y) = pos2xy(map["snakeInfos"][j]["positions"][i], map["width"]);
      int dist_x = i_x - snake_x;
      int dist_y = i_y - snake_y;

      if (dist_y > -view_distance && dist_y < 0  && abs(dist_x) < view_distance) // danger up
      {
        danger[0] += (view_distance + dist_y)*(view_distance + dist_y)*(view_distance + dist_y);
      }
      else if (dist_y > 0 && dist_y < view_distance  && abs(dist_x) < view_distance) //  danger down
      {
        danger[1] += (view_distance - dist_y)*(view_distance - dist_y)*(view_distance - dist_y);
      }

      if (dist_x > -view_distance && dist_x < 0  && abs(dist_y) < view_distance)
      {
        danger[3] += (view_distance + dist_x)*(view_distance + dist_x)*(view_distance + dist_x);
      }
      else if (dist_x > 0 && dist_x < view_distance && abs(dist_y) < view_distance)
      {
        danger[2] += (view_distance - dist_y)*(view_distance - dist_y)*(view_distance - dist_y);
      }
    }
  }

  // WALLS
  if (snake_y < 5)
  {
    danger[0] += 10*(5 - snake_y)*(5 - snake_y);
  }
  if (mapHight - snake_y < 5)
  {
    danger[1] += 10*(5 - mapHight + snake_y)*(5 - mapHight + snake_y);
  }
  if (snake_x < 5)
  {
    danger[3] += 10*(5 - snake_x)*(5 - snake_x);
  }
  if (mapWidth - snake_x < 5)
  {
    danger[2] += 10*(5 - mapWidth + snake_x)*(5 - mapWidth + snake_x);
  }

  // if last move was up you cant go down next move if lastMove = 0
  /*
  0 - up
  1 - down
  2- right
  3- left
  */

  // Avoid your last move
  if(lastMove == 0){
    avoidedMove = 1;
  }
  else if(lastMove == 1){
    avoidedMove = 0;
  }
  else if(lastMove == 2){
    avoidedMove = 3;
  }
  else{
    avoidedMove = 2;
  }
  danger[avoidedMove] += 1000;
  // Is not dangerous and food close, is not dagerous or food close
  int best_choice = 0;
  double choice_value = 1000;
  for (int i = 0; i < 4; ++i)
  {
    //LOG(INFO) << "dir: " << i << " d: " << danger[i] << " f: " << food[i];
    if (danger[i] - food[i] < choice_value) // is good choice and better then the chosen one
    {
      best_choice = i;
      choice_value = danger[i] - food[i];
    }
  }

  lastMove = best_choice;

  //LOG(INFO) << "Snake is making move " << responsArray[best_choice] << " at worldtick: " << map["worldTick"];
  return responsArray[best_choice];

};
// ---------------------- OUR FUNCTIONS -------------------------------
void Snake::initializeCurves(){
  curveFood[0]= 10;
  curveFood[1]= 5;
  curveFood[2]= 2.5;
  curveFood[3]= 1.25;
  curveFood[4]= 0;

  curveWall[0]= -30;
  curveWall[1]= -20;
  curveWall[2]= -10;
  curveWall[3]= -5;
  curveWall[4]= 0;

  curvePlayers[0]= -10;
  curvePlayers[1]= -5;
  curvePlayers[2]= -2.5;
  curvePlayers[3]= -1.25;
  curvePlayers[4]= 0;

  curveTail[0]= 0;
  curveTail[1]= 0;
  curveTail[2]= 0;
  curveTail[3]= 0;
  curveTail[4]= 0;

  curveObstacle[0]= -30;
  curveObstacle[1]= -20;
  curveObstacle[2]= -10;
  curveObstacle[3]= -5;
  curveObstacle[4]= 0;

}

// From int pos to x,y coords
std::tuple<int, int> Snake::pos2xy(const int position, const int map_width) {
  float pos = position;
  float width = map_width;

  int y = floor(pos / width);
  int x = fabs(pos - y * width);

  return std::make_tuple(x, y);
}

int Snake::xy2pos(const int x, const int y, const int map_width) {
  int res =  x + y * map_width;
  return res;
}

 // ---------------------- THERE FUNCTIONS -------------------------------
void Snake::on_game_ended() {
  LOG(INFO) << "Game has ended";
};

void Snake::on_tournament_ended() {
  LOG(INFO) << "Tournament has ended";
};

void Snake::on_snake_dead(std::string death_reason) {
  LOG(INFO) << "Our snake has died, reason was: " << death_reason;
};

void Snake::on_game_starting() {
  mySnakeSlot = -1;
  LOG(INFO) << "Game is starting";
  // Leta upp din snake ?
  initializeCurves();
  lastMove = 0;
  LOG(INFO) << "initializeCurves finnished";

};

void Snake::on_player_registered() {
  LOG(INFO) << "Player was successfully registered";
};

void Snake::on_invalid_playername() {
  LOG(INFO) << "The player name is invalid, try another?";
};

void Snake::on_game_result(nlohmann::json playerRanks) {
  LOG(INFO) << "Game result:";
  nlohmann::json playerRank;
  el::Logger* defaultLogger = el::Loggers::getLogger("default");
  for (json::iterator it = playerRanks.begin(); it != playerRanks.end(); ++it) {
    playerRank = (nlohmann::json) *it;
    defaultLogger->info("%v.\t%v pts\t%v (%v)", playerRank["rank"], playerRank["points"],
            playerRank["playerName"], playerRank["alive"] ? "alive" : "dead");
  }
};
;

<commit_msg>new good run<commit_after>#include "easylogging++.h"
#include "json.hpp"
#include "snake.h"

using nlohmann::json;

// Good runs:   http://game.snake.cygni.se/#/viewgame/88a759cf-e406-4941-9eba-28d51ed9c600
//              http://game.snake.cygni.se/#/viewgame/af42c3a4-fbf9-4a14-b892-3fdf6da063a4
//              http://game.snake.cygni.se/#/viewgame/ed59e861-8147-4845-8f6c-3b586b2b91a4
//              http://game.snake.cygni.se/#/viewgame/9645084f-3969-4c84-88ca-35be7cbd8216 (distant 4)
//              http://game.snake.cygni.se/#/viewgame/820f1c8b-77f3-4734-93ad-d5d9f5e424b2 (my good run)

// Postionen ges av int position => endast ett värde på mappen

// ---------------------- NEXT MOOVE  -------------------------------

std::string Snake::get_next_move(json map) {
  int mapHight = map["height"] ;
  int mapWidth = map["width"] ;

  //int response = 1;
  std::string responsArray [] = {"UP", "DOWN", "RIGHT", "LEFT"};

   std::array<double,4> responsValue;

  // Reset responsValue
  responsValue[0] = 0; // UP
  responsValue[1] = 0; // DOWN
  responsValue[2] = 0; // RIGHT
  responsValue[3] = 0; // LEFT

  // Hitta vår snake första gången vi spelar
  if(mySnakeSlot == -1){
  mySnakeSlot = 0;
      while(map["snakeInfos"][mySnakeSlot]["name"] != name){
        mySnakeSlot++;
      }
  }

  int snake_x, snake_y;
  std::tie(snake_x,snake_y) = pos2xy(map["snakeInfos"][mySnakeSlot]["positions"][0], map["width"]);
  // LOG(INFO) << "Snake pos: " << x << ", " << y ;
  //

  double danger[] = {0.0, 0.0, 0.0, 0.0};
  double food[] = {0.0, 0.0, 0.0, 0.0};
  int view_distance = 2;

  for (int i = 0; i < map["obstaclePositions"].size(); ++i) // OBSTACLE
  {
    int i_x, i_y;
    std::tie(i_x,i_y) = pos2xy(map["obstaclePositions"][i], map["width"]);
    int dist_x = i_x - snake_x;
    int dist_y = i_y - snake_y;

    if (dist_y > -view_distance && dist_y < 0 && abs(dist_x) < view_distance) // danger up
    {
      danger[0] += (view_distance + dist_y)*(view_distance + dist_y);
    }
    else if (dist_y > 0 && dist_y < view_distance  && abs(dist_x) < view_distance) //  danger down
    {
      danger[1] += (view_distance - dist_y)*(view_distance - dist_y);
    }

    if (dist_x > -view_distance && dist_x < 0  && abs(dist_y) < view_distance)
    {
      danger[3] += (view_distance + dist_x)*(view_distance + dist_x);
    }
    else if (dist_x > 0 && dist_x < view_distance  && abs(dist_y) < view_distance)
    {
      danger[2] += (view_distance - dist_y)*(view_distance - dist_y);
    }

  }

  for (int i = 0; i < map["foodPositions"].size(); ++i) // FOOD
  {
    int i_x, i_y;
    std::tie(i_x,i_y) = pos2xy(map["foodPositions"][i], map["width"]);
    int dist_x = i_x - snake_x;
    int dist_y = i_y - snake_y;

    if (dist_y > -view_distance && dist_y < 0 && abs(dist_x) < view_distance)
    {
      food[0] += (view_distance + dist_y)*(view_distance + dist_y);
    }
    else if (dist_y > 0 && dist_y < view_distance  && abs(dist_x) < view_distance)
    {
      food[1] += (view_distance - dist_y)*(view_distance - dist_y);
    }

    if (dist_x > -view_distance && dist_x < 0  && abs(dist_y) < view_distance)
    {
      food[3] += (view_distance + dist_x)*(view_distance + dist_x);
    }
    else if (dist_x > 0 && dist_x < view_distance  && abs(dist_y) < view_distance)
    {
      food[2] += (view_distance - dist_y)*(view_distance - dist_y);
    }
  }

  for (int j = 0; j < map["snakeInfos"].size(); ++j) // SNAKES (including yourself)
  {
    for (int i = 0; i < map["snakeInfos"][j]["positions"].size(); ++i)
    {
      int i_x, i_y;
      std::tie(i_x,i_y) = pos2xy(map["snakeInfos"][j]["positions"][i], map["width"]);
      int dist_x = i_x - snake_x;
      int dist_y = i_y - snake_y;

      if (dist_y > -view_distance && dist_y < 0  && abs(dist_x) < view_distance) // danger up
      {
        danger[0] += (view_distance + dist_y)*(view_distance + dist_y)*(view_distance + dist_y);
      }
      else if (dist_y > 0 && dist_y < view_distance  && abs(dist_x) < view_distance) //  danger down
      {
        danger[1] += (view_distance - dist_y)*(view_distance - dist_y)*(view_distance - dist_y);
      }

      if (dist_x > -view_distance && dist_x < 0  && abs(dist_y) < view_distance)
      {
        danger[3] += (view_distance + dist_x)*(view_distance + dist_x)*(view_distance + dist_x);
      }
      else if (dist_x > 0 && dist_x < view_distance && abs(dist_y) < view_distance)
      {
        danger[2] += (view_distance - dist_y)*(view_distance - dist_y)*(view_distance - dist_y);
      }
    }
  }

  // WALLS
  if (snake_y < view_distance)
  {
    danger[0] += 3*(view_distance - snake_y)*(view_distance - snake_y);
  }
  if (mapHight - snake_y < view_distance)
  {
    danger[1] += 3*(view_distance - mapHight + snake_y)*(view_distance - mapHight + snake_y);
  }
  if (snake_x < view_distance)
  {
    danger[3] += 3*(view_distance - snake_x)*(view_distance - snake_x);
  }
  if (mapWidth - snake_x < view_distance)
  {
    danger[2] += 3*(view_distance - mapWidth + snake_x)*(view_distance - mapWidth + snake_x);
  }

  // if last move was up you cant go down next move if lastMove = 0
  /*
  0 - up
  1 - down
  2- right
  3- left
  */

  // Avoid your last move
  if(lastMove == 0){
    avoidedMove = 1;
  }
  else if(lastMove == 1){
    avoidedMove = 0;
  }
  else if(lastMove == 2){
    avoidedMove = 3;
  }
  else{
    avoidedMove = 2;
  }
  danger[avoidedMove] += 1000;
  // Is not dangerous and food close, is not dagerous or food close
  int best_choice = 0;
  double choice_value = 1000;
  for (int i = 0; i < 4; ++i)
  {
    LOG(INFO) << "dir: " << i << " d: " << danger[i] << " f: " << food[i];
    if (danger[i] - food[i] < choice_value) // is good choice and better then the chosen one
    {
      best_choice = i;
      choice_value = danger[i] - food[i];
    }
  }

  lastMove = best_choice;

  LOG(INFO) << "Snake is making move " << responsArray[best_choice] << " at worldtick: " << map["worldTick"];
  return responsArray[best_choice];

};
// ---------------------- OUR FUNCTIONS -------------------------------
void Snake::initializeCurves(){
  curveFood[0]= 10;
  curveFood[1]= 5;
  curveFood[2]= 2.5;
  curveFood[3]= 1.25;
  curveFood[4]= 0;

  curveWall[0]= -30;
  curveWall[1]= -20;
  curveWall[2]= -10;
  curveWall[3]= -5;
  curveWall[4]= 0;

  curvePlayers[0]= -10;
  curvePlayers[1]= -5;
  curvePlayers[2]= -2.5;
  curvePlayers[3]= -1.25;
  curvePlayers[4]= 0;

  curveTail[0]= 0;
  curveTail[1]= 0;
  curveTail[2]= 0;
  curveTail[3]= 0;
  curveTail[4]= 0;

  curveObstacle[0]= -30;
  curveObstacle[1]= -20;
  curveObstacle[2]= -10;
  curveObstacle[3]= -5;
  curveObstacle[4]= 0;

}

// From int pos to x,y coords
std::tuple<int, int> Snake::pos2xy(const int position, const int map_width) {
  float pos = position;
  float width = map_width;

  int y = floor(pos / width);
  int x = fabs(pos - y * width);

  return std::make_tuple(x, y);
}

int Snake::xy2pos(const int x, const int y, const int map_width) {
  int res =  x + y * map_width;
  return res;
}

 // ---------------------- THERE FUNCTIONS -------------------------------
void Snake::on_game_ended() {
  LOG(INFO) << "Game has ended";
};

void Snake::on_tournament_ended() {
  LOG(INFO) << "Tournament has ended";
};

void Snake::on_snake_dead(std::string death_reason) {
  LOG(INFO) << "Our snake has died, reason was: " << death_reason;
};

void Snake::on_game_starting() {
  mySnakeSlot = -1;
  LOG(INFO) << "Game is starting";
  // Leta upp din snake ?
  initializeCurves();
  lastMove = 0;
  LOG(INFO) << "initializeCurves finnished";

};

void Snake::on_player_registered() {
  LOG(INFO) << "Player was successfully registered";
};

void Snake::on_invalid_playername() {
  LOG(INFO) << "The player name is invalid, try another?";
};

void Snake::on_game_result(nlohmann::json playerRanks) {
  LOG(INFO) << "Game result:";
  nlohmann::json playerRank;
  el::Logger* defaultLogger = el::Loggers::getLogger("default");
  for (json::iterator it = playerRanks.begin(); it != playerRanks.end(); ++it) {
    playerRank = (nlohmann::json) *it;
    defaultLogger->info("%v.\t%v pts\t%v (%v)", playerRank["rank"], playerRank["points"],
            playerRank["playerName"], playerRank["alive"] ? "alive" : "dead");
  }
};
;

<|endoftext|>


<commit_before>#ifndef string_hh_INCLUDED
#define string_hh_INCLUDED

#include <string>
#include <iosfwd>
#include <climits>
#include <boost/regex.hpp>

#include "memoryview.hh"
#include "units.hh"
#include "utf8.hh"

namespace Kakoune
{

typedef boost::regex Regex;

class String
{
public:
   String() {}
   String(const char* content) : m_content(content) {}
   String(std::string content) : m_content(std::move(content)) {}
   String(const String& string) = default;
   String(String&& string) = default;
   explicit String(char content, CharCount count = 1) : m_content((size_t)(int)count, content) {}
   template<typename Iterator>
   String(Iterator begin, Iterator end) : m_content(begin, end) {}

   char      operator[](ByteCount pos) const { return m_content[(int)pos]; }
   ByteCount length() const { return m_content.length(); }
   CharCount char_length() const { return utf8::distance(begin(), end()); }
   ByteCount byte_count_to(CharCount count) const { return utf8::advance(begin(), end(), (int)count) - begin(); }
   CharCount char_count_to(ByteCount count) const { return utf8::distance(begin(), begin() + (int)count); }
   bool      empty()  const { return m_content.empty(); }

   bool      operator== (const String& other) const { return m_content == other.m_content; }
   bool      operator!= (const String& other) const { return m_content != other.m_content; }
   bool      operator<  (const String& other) const { return m_content < other.m_content;  }

   String&   operator=  (const String& other)       { m_content = other.m_content; return *this; }
   String&   operator=  (String&& other)            { m_content = std::move(other.m_content); return *this; }

   String    operator+  (const String& other) const { return String(m_content + other.m_content); }
   String&   operator+= (const String& other)       { m_content += other.m_content; return *this; }

   String    operator+  (char c) const { return String(m_content + c); }
   String&   operator+= (char c)       { m_content += c; return *this; }

   memoryview<char> data()  const { return memoryview<char>(m_content.data(), m_content.size()); }
   const char*      c_str() const { return m_content.c_str(); }

   String substr(ByteCount pos, ByteCount length = -1) const { return String(m_content.substr((int)pos, (int)length)); }
   String substr(CharCount pos, CharCount length = INT_MAX) const
   {
       auto b = utf8::advance(begin(), end(), (int)pos);
       auto e = utf8::advance(b, end(), (int)length);
       return String(b,e);
   }
   String replace(const String& expression, const String& replacement) const;

   using iterator = std::string::const_iterator;

   iterator begin() const { return m_content.begin(); }
   iterator end()   const { return m_content.end(); }

   char     front() const { return m_content.front(); }
   char     back()  const { return m_content.back(); }
   char&    front()       { return m_content.front(); }
   char&    back()        { return m_content.back(); }

   size_t   hash() const { return std::hash<std::string>()(m_content); }

   inline friend std::ostream& operator<<(std::ostream& os, const String& str)
   {
       return os << str.m_content;
   }

   enum { npos = -1 };

private:
   std::string m_content;
};

inline String operator+(const char* lhs, const String& rhs)
{
    return String(lhs) + rhs;
}

inline String operator+(char lhs, const String& rhs)
{
    return String(lhs) + rhs;
}

String int_to_str(int value);
int    str_to_int(const String& str);
std::vector<String> split(const String& str, char separator);

inline String operator"" _str(const char* str, size_t)
{
    return String(str);
}

inline String codepoint_to_str(Codepoint cp)
{
    std::string str;
    auto it = back_inserter(str);
    utf8::dump(it, cp);
    return String(str);
}

}

namespace std
{
    template<>
    struct hash<Kakoune::String>
    {
        size_t operator()(const Kakoune::String& str) const
        {
            return str.hash();
        }
    };
}

#endif // string_hh_INCLUDED

<commit_msg>Add a String(Codepoint, CharCount) constructor<commit_after>#ifndef string_hh_INCLUDED
#define string_hh_INCLUDED

#include <string>
#include <iosfwd>
#include <climits>
#include <boost/regex.hpp>

#include "memoryview.hh"
#include "units.hh"
#include "utf8.hh"

namespace Kakoune
{

typedef boost::regex Regex;

class String
{
public:
   String() {}
   String(const char* content) : m_content(content) {}
   String(std::string content) : m_content(std::move(content)) {}
   String(const String& string) = default;
   String(String&& string) = default;
   explicit String(char content, CharCount count = 1) : m_content((size_t)(int)count, content) {}
   explicit String(Codepoint cp, CharCount count = 1)
   {
       std::string str;
       auto it = back_inserter(str);
       utf8::dump(it, cp);
       for (CharCount i = 0; i < count; ++i)
           m_content += str;
   }
   template<typename Iterator>
   String(Iterator begin, Iterator end) : m_content(begin, end) {}

   char      operator[](ByteCount pos) const { return m_content[(int)pos]; }
   ByteCount length() const { return m_content.length(); }
   CharCount char_length() const { return utf8::distance(begin(), end()); }
   ByteCount byte_count_to(CharCount count) const { return utf8::advance(begin(), end(), (int)count) - begin(); }
   CharCount char_count_to(ByteCount count) const { return utf8::distance(begin(), begin() + (int)count); }
   bool      empty()  const { return m_content.empty(); }

   bool      operator== (const String& other) const { return m_content == other.m_content; }
   bool      operator!= (const String& other) const { return m_content != other.m_content; }
   bool      operator<  (const String& other) const { return m_content < other.m_content;  }

   String&   operator=  (const String& other)       { m_content = other.m_content; return *this; }
   String&   operator=  (String&& other)            { m_content = std::move(other.m_content); return *this; }

   String    operator+  (const String& other) const { return String(m_content + other.m_content); }
   String&   operator+= (const String& other)       { m_content += other.m_content; return *this; }

   String    operator+  (char c) const { return String(m_content + c); }
   String&   operator+= (char c)       { m_content += c; return *this; }

   memoryview<char> data()  const { return memoryview<char>(m_content.data(), m_content.size()); }
   const char*      c_str() const { return m_content.c_str(); }

   String substr(ByteCount pos, ByteCount length = -1) const { return String(m_content.substr((int)pos, (int)length)); }
   String substr(CharCount pos, CharCount length = INT_MAX) const
   {
       auto b = utf8::advance(begin(), end(), (int)pos);
       auto e = utf8::advance(b, end(), (int)length);
       return String(b,e);
   }
   String replace(const String& expression, const String& replacement) const;

   using iterator = std::string::const_iterator;

   iterator begin() const { return m_content.begin(); }
   iterator end()   const { return m_content.end(); }

   char     front() const { return m_content.front(); }
   char     back()  const { return m_content.back(); }
   char&    front()       { return m_content.front(); }
   char&    back()        { return m_content.back(); }

   size_t   hash() const { return std::hash<std::string>()(m_content); }

   inline friend std::ostream& operator<<(std::ostream& os, const String& str)
   {
       return os << str.m_content;
   }

   enum { npos = -1 };

private:
   std::string m_content;
};

inline String operator+(const char* lhs, const String& rhs)
{
    return String(lhs) + rhs;
}

inline String operator+(char lhs, const String& rhs)
{
    return String(lhs) + rhs;
}

String int_to_str(int value);
int    str_to_int(const String& str);
std::vector<String> split(const String& str, char separator);

inline String operator"" _str(const char* str, size_t)
{
    return String(str);
}

inline String codepoint_to_str(Codepoint cp)
{
    std::string str;
    auto it = back_inserter(str);
    utf8::dump(it, cp);
    return String(str);
}

}

namespace std
{
    template<>
    struct hash<Kakoune::String>
    {
        size_t operator()(const Kakoune::String& str) const
        {
            return str.hash();
        }
    };
}

#endif // string_hh_INCLUDED

<|endoftext|>