<commit_before>// LaminaFS is Copyright (c) 2016 Brett Lajzer
// See LICENSE for license information.

#include "Directory.h"

#include <cstdio>
#include <cstring>

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#ifdef _WIN32
#define UNICODE 1
#define _UNICODE 1
#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>
#include <shellapi.h>
#else
#include <fts.h>
#include <unistd.h>
#endif

using namespace laminaFS;

namespace {
#ifdef _WIN32
constexpr uint32_t MAX_PATH_LEN = 1024;

int widen(const char *inStr, WCHAR *outStr, size_t outStrLen) {
	return MultiByteToWideChar(CP_UTF8, 0, inStr, -1, outStr, (int)outStrLen);
}

ErrorCode convertError(DWORD error) {
	ErrorCode result = LFS_GENERIC_ERROR;

	switch (error) {
	case ERROR_FILE_NOT_FOUND:
	case ERROR_PATH_NOT_FOUND:
		result = LFS_NOT_FOUND;
		break;
	case ERROR_ACCESS_DENIED:
		result = LFS_PERMISSIONS_ERROR;
		break;
	};

	return result;
}

#else
ErrorCode convertError(int error) {
	ErrorCode result = LFS_GENERIC_ERROR;

	switch (error) {
	case EEXIST:
		result = LFS_ALREADY_EXISTS;
		break;
	case EPERM:
	case EACCES:
		result = LFS_PERMISSIONS_ERROR;
		break;
	case EROFS:
		result = LFS_UNSUPPORTED;
		break;
	case ENOENT:
		result = LFS_NOT_FOUND;
		break;
	}

	return result;
}
#endif
}

DirectoryDevice::DirectoryDevice(Allocator *allocator, const char *path) {
	_alloc = allocator;

	// TODO: realpath()
	_pathLen = static_cast<uint32_t>(strlen(path));
	_devicePath = reinterpret_cast<char*>(_alloc->alloc(_alloc->allocator, sizeof(char) * (_pathLen + 1), alignof(char)));
	strcpy(_devicePath, path);
}

DirectoryDevice::~DirectoryDevice() {
	_alloc->free(_alloc->allocator, _devicePath);
}

ErrorCode DirectoryDevice::create(Allocator *alloc, const char *path, void **device) {
	ErrorCode returnCode = LFS_OK;
#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(path, &windowsPath[0], MAX_PATH_LEN);

	DWORD result = GetFileAttributesW(&windowsPath[0]);

	if (result != INVALID_FILE_ATTRIBUTES && (result & FILE_ATTRIBUTE_DIRECTORY)) {
		*device = new(alloc->alloc(alloc->allocator, sizeof(DirectoryDevice), alignof(DirectoryDevice))) DirectoryDevice(alloc, path);
	} else {
		returnCode = LFS_NOT_FOUND;
	}
#else
	struct stat statInfo;
	int result = stat(path, &statInfo);

	if (result == 0 && S_ISDIR(statInfo.st_mode)) {
		*device = new(alloc->alloc(alloc->allocator, sizeof(DirectoryDevice), alignof(DirectoryDevice))) DirectoryDevice(alloc, path);
	} else {
		*device = nullptr;
		returnCode = LFS_NOT_FOUND;
	}
#endif

	return returnCode;
}

void DirectoryDevice::destroy(void *device) {
	DirectoryDevice *dir = static_cast<DirectoryDevice *>(device);
	dir->~DirectoryDevice();
	dir->_alloc->free(dir->_alloc->allocator, device);
}

#ifdef _WIN32
void *DirectoryDevice::openFile(const char *filePath, uint32_t accessMode, uint32_t createMode) {
	char *diskPath = getDevicePath(filePath);
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(diskPath, &windowsPath[0], MAX_PATH_LEN);
	freeDevicePath(diskPath);

	HANDLE file = CreateFileW(
		&windowsPath[0],
		accessMode,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		nullptr,
		createMode,
		FILE_ATTRIBUTE_NORMAL,
		nullptr);

	return file;
}
#else
FILE *DirectoryDevice::openFile(const char *filePath, const char *modeString) {
	char *diskPath = getDevicePath(filePath);
	FILE *file = fopen(diskPath, modeString);
	freeDevicePath(diskPath);
	return file;
}
#endif

char *DirectoryDevice::getDevicePath(const char *filePath) {
	uint32_t diskPathLen = static_cast<uint32_t>(_pathLen + strlen(filePath) + 1);
	char *diskPath = reinterpret_cast<char*>(_alloc->alloc(_alloc->allocator, sizeof(char) * diskPathLen, alignof(char)));
	strcpy(diskPath, _devicePath);
	strcpy(diskPath + _pathLen, filePath);

	// replace forward slashes with backslashes on windows
#ifdef _WIN32
	for (uint32_t i = 0; i < diskPathLen; ++i) {
		if (diskPath[i] == '/')
			diskPath[i] = '\\';
	}
#endif

	return diskPath;
}

void DirectoryDevice::freeDevicePath(char *path) {
	_alloc->free(_alloc->allocator, path);
}

bool DirectoryDevice::fileExists(void *device, const char *filePath) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	char *diskPath = dev->getDevicePath(filePath);

#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(diskPath, &windowsPath[0], MAX_PATH_LEN);
	dev->freeDevicePath(diskPath);

	DWORD result = GetFileAttributesW(&windowsPath[0]);

	return result != INVALID_FILE_ATTRIBUTES && !(result & FILE_ATTRIBUTE_DIRECTORY);
#else
	struct stat statInfo;
	int result = stat(diskPath, &statInfo);

	dev->freeDevicePath(diskPath);
	return result == 0 && S_ISREG(statInfo.st_mode);
#endif
}

size_t DirectoryDevice::fileSize(void *device, const char *filePath, ErrorCode *outError) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	size_t size = 0;

#ifdef _WIN32
	HANDLE file = dev->openFile(filePath, GENERIC_READ, OPEN_EXISTING);

	if (file) {
		LARGE_INTEGER result;
		if(!GetFileSizeEx(file, &result)) {
			printf("error code %lu\n", GetLastError());
		} else {
			size = result.QuadPart;
		}
		CloseHandle(file);
	} else {
		*outError = convertError(GetLastError());
	}
#else
	char *diskPath = dev->getDevicePath(filePath);
	struct stat statInfo;
	int result = stat(diskPath, &statInfo);
	dev->freeDevicePath(diskPath);

	if (result == 0 && S_ISREG(statInfo.st_mode)) {
		*outError = LFS_OK;
		size = statInfo.st_size;
	} else if (result != 0) {
		*outError = convertError(errno);
	} else {
	   *outError = LFS_UNSUPPORTED;
	}
#endif
	return size;
}

size_t DirectoryDevice::readFile(void *device, const char *filePath, Allocator *alloc, void **buffer, bool nullTerminate, ErrorCode *outError) {
	size_t bytesRead = 0;
	DirectoryDevice *dir = static_cast<DirectoryDevice*>(device);
#ifdef _WIN32
	HANDLE file = dir->openFile(filePath, GENERIC_READ, OPEN_EXISTING);

	if (file) {
		LARGE_INTEGER result;
		GetFileSizeEx(file, &result);
		size_t fileSize = result.QuadPart;

		if (fileSize) {
			*buffer = dir->_alloc->alloc(dir->_alloc->allocator, fileSize + (nullTerminate ? 1 : 0), 1);

			DWORD bytesReadTemp = 0;
			if (!ReadFile(file, *buffer, (DWORD)fileSize, &bytesReadTemp, nullptr)) {
				*outError = convertError(GetLastError());
			} else if (nullTerminate) {
				(*(char**)buffer)[bytesRead] = 0;
			}

			bytesRead = bytesReadTemp;
		}

		CloseHandle(file);
	} else {
		*outError = LFS_NOT_FOUND;
	}
#else
	FILE *file = dir->openFile(filePath, "rb");

	if (file) {
		size_t fileSize = 0;
		if (fseek(file, 0L, SEEK_END) == 0) {
			fileSize = ftell(file);
		}

		if (fileSize && fseek(file, 0L, SEEK_SET) == 0) {
			*buffer = dir->_alloc->alloc(dir->_alloc->allocator, fileSize + (nullTerminate ? 1 : 0), 1);
			if (*buffer) {
				bytesRead = fread(*buffer, 1, fileSize, file);

				if (nullTerminate) {
					(*(char**)buffer)[bytesRead] = 0;
				}
			}
		}

		*outError = ferror(file) ? LFS_GENERIC_ERROR : LFS_OK;

		fclose(file);
	} else {
		*outError = LFS_NOT_FOUND;
	}
#endif
	return bytesRead;
}

size_t DirectoryDevice::writeFile(void *device, const char *filePath, void *buffer, size_t bytesToWrite, bool append, ErrorCode *outError) {
	size_t bytesWritten = 0;
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);

#ifdef _WIN32
	HANDLE file = dev->openFile(filePath, GENERIC_WRITE, append ? OPEN_ALWAYS : CREATE_ALWAYS);

	if (file) {
		if (append) {
			if (SetFilePointer(file, 0, nullptr, FILE_END) == INVALID_SET_FILE_POINTER) {
				*outError = LFS_GENERIC_ERROR;
				CloseHandle(file);
				return bytesWritten;
			}
		}

		DWORD temp = 0;
		if (!WriteFile(file, buffer, (DWORD)bytesToWrite, &temp, nullptr)) {
				*outError = LFS_GENERIC_ERROR;
		} else {
			bytesWritten = temp;
		}
	} else {
		*outError = convertError(GetLastError());
	}

	CloseHandle(file);
#else
	FILE *file = dev->openFile(filePath, append ? "ab" : "wb");

	if (file) {
		bytesWritten = fwrite(buffer, 1, bytesToWrite, file);
		*outError = ferror(file) ? LFS_GENERIC_ERROR : LFS_OK;
		fclose(file);
	} else {
		*outError = LFS_PERMISSIONS_ERROR;
	}
#endif
	return bytesWritten;
}

ErrorCode DirectoryDevice::deleteFile(void *device, const char *filePath) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	char *diskPath = dev->getDevicePath(filePath);

	ErrorCode resultCode = LFS_OK;
#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(diskPath, &windowsPath[0], MAX_PATH_LEN);

	if (!DeleteFileW(&windowsPath[0])) {
		resultCode = convertError(GetLastError());
	}
#else
	if (unlink(diskPath) != 0) {
		resultCode = convertError(errno);
	}
#endif

	dev->freeDevicePath(diskPath);
	return resultCode;
}

ErrorCode DirectoryDevice::createDir(void *device, const char *path) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	char *diskPath = dev->getDevicePath(path);

	ErrorCode resultCode = LFS_OK;
#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(diskPath, &windowsPath[0], MAX_PATH_LEN);

	if (!CreateDirectoryW(&windowsPath[0], nullptr)) {
		resultCode = convertError(GetLastError());
	}
#else
	int result = mkdir(diskPath, DEFFILEMODE | S_IXUSR | S_IXGRP | S_IRWXO);

	if (result != 0) {
		resultCode = convertError(errno);
	}
#endif

	dev->freeDevicePath(diskPath);
	return resultCode;
}

ErrorCode DirectoryDevice::deleteDir(void *device, const char *path) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	char *diskPath = dev->getDevicePath(path);

	ErrorCode resultCode = LFS_OK;

#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	int len = widen(diskPath, &windowsPath[0], MAX_PATH_LEN - 1); // XXX: ensure one space for double-null
	windowsPath[len] = 0;

	// just use the shell API to delete the directory.
	// requires path to be double null-terminated.
	// https://msdn.microsoft.com/en-us/library/windows/desktop/bb762164(v=vs.85).aspx
	SHFILEOPSTRUCTW shOp;
	shOp.hwnd = nullptr;
	shOp.wFunc = FO_DELETE;
	shOp.pFrom = &windowsPath[0];
	shOp.pTo = nullptr;
	shOp.fFlags = FOF_NO_UI;
	shOp.fAnyOperationsAborted = FALSE;
	shOp.hNameMappings = nullptr;
	shOp.lpszProgressTitle = nullptr;

	int result = SHFileOperationW(&shOp);

	switch (result) {
	case 0:
		break;
	case 0x7C: // DE_INVALIDFILES
		resultCode = LFS_NOT_FOUND;
		break;
	case 0x78: // DE_ACCESSDENIEDSRC
	case 0x86: // DE_SRC_IS_CDROM
	case 0x87: // DE_SRC_IS_DVD
		resultCode = LFS_PERMISSIONS_ERROR;
		break;
	default:
		resultCode = LFS_GENERIC_ERROR;
		break;
	};
#else
	FTS *fts = nullptr;
	char *fileList[] = {diskPath, nullptr};
	bool error = false;

	if ((fts = fts_open(fileList, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
		FTSENT *ent = fts_read(fts);
		while (!error && ent) {
			switch (ent->fts_info) {
			// ignore directories until post-traversal (FTS_DP)
			case FTS_D:
				break;

			// normal stuff we want to delete
			case FTS_DEFAULT:
			case FTS_DP:
			case FTS_F:
			case FTS_SL:
			case FTS_SLNONE:
				if (remove(ent->fts_accpath) == -1) {
					error = true;
				}
				break;

			// shouldn't ever hit these
			case FTS_DC:
			case FTS_DOT:
			case FTS_NSOK:
				break;

			// errors
			case FTS_NS:
			case FTS_DNR:
			case FTS_ERR:
				error = true;
				errno = ent->fts_errno;
				break;
			};

			if (!error)
				ent = fts_read(fts);
		}

		error = error || errno != 0;
		fts_close(fts);
	}

	if (error) {
		resultCode = convertError(errno);
	}
#endif

	dev->freeDevicePath(diskPath);
	return resultCode;
}
<commit_msg>Use the correct allocator when reading files.<commit_after>// LaminaFS is Copyright (c) 2016 Brett Lajzer
// See LICENSE for license information.

#include "Directory.h"

#include <cstdio>
#include <cstring>

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#ifdef _WIN32
#define UNICODE 1
#define _UNICODE 1
#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>
#include <shellapi.h>
#else
#include <fts.h>
#include <unistd.h>
#endif

using namespace laminaFS;

namespace {
#ifdef _WIN32
constexpr uint32_t MAX_PATH_LEN = 1024;

int widen(const char *inStr, WCHAR *outStr, size_t outStrLen) {
	return MultiByteToWideChar(CP_UTF8, 0, inStr, -1, outStr, (int)outStrLen);
}

ErrorCode convertError(DWORD error) {
	ErrorCode result = LFS_GENERIC_ERROR;

	switch (error) {
	case ERROR_FILE_NOT_FOUND:
	case ERROR_PATH_NOT_FOUND:
		result = LFS_NOT_FOUND;
		break;
	case ERROR_ACCESS_DENIED:
		result = LFS_PERMISSIONS_ERROR;
		break;
	};

	return result;
}

#else
ErrorCode convertError(int error) {
	ErrorCode result = LFS_GENERIC_ERROR;

	switch (error) {
	case EEXIST:
		result = LFS_ALREADY_EXISTS;
		break;
	case EPERM:
	case EACCES:
		result = LFS_PERMISSIONS_ERROR;
		break;
	case EROFS:
		result = LFS_UNSUPPORTED;
		break;
	case ENOENT:
		result = LFS_NOT_FOUND;
		break;
	}

	return result;
}
#endif
}

DirectoryDevice::DirectoryDevice(Allocator *allocator, const char *path) {
	_alloc = allocator;

	// TODO: realpath()
	_pathLen = static_cast<uint32_t>(strlen(path));
	_devicePath = reinterpret_cast<char*>(_alloc->alloc(_alloc->allocator, sizeof(char) * (_pathLen + 1), alignof(char)));
	strcpy(_devicePath, path);
}

DirectoryDevice::~DirectoryDevice() {
	_alloc->free(_alloc->allocator, _devicePath);
}

ErrorCode DirectoryDevice::create(Allocator *alloc, const char *path, void **device) {
	ErrorCode returnCode = LFS_OK;
#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(path, &windowsPath[0], MAX_PATH_LEN);

	DWORD result = GetFileAttributesW(&windowsPath[0]);

	if (result != INVALID_FILE_ATTRIBUTES && (result & FILE_ATTRIBUTE_DIRECTORY)) {
		*device = new(alloc->alloc(alloc->allocator, sizeof(DirectoryDevice), alignof(DirectoryDevice))) DirectoryDevice(alloc, path);
	} else {
		returnCode = LFS_NOT_FOUND;
	}
#else
	struct stat statInfo;
	int result = stat(path, &statInfo);

	if (result == 0 && S_ISDIR(statInfo.st_mode)) {
		*device = new(alloc->alloc(alloc->allocator, sizeof(DirectoryDevice), alignof(DirectoryDevice))) DirectoryDevice(alloc, path);
	} else {
		*device = nullptr;
		returnCode = LFS_NOT_FOUND;
	}
#endif

	return returnCode;
}

void DirectoryDevice::destroy(void *device) {
	DirectoryDevice *dir = static_cast<DirectoryDevice *>(device);
	dir->~DirectoryDevice();
	dir->_alloc->free(dir->_alloc->allocator, device);
}

#ifdef _WIN32
void *DirectoryDevice::openFile(const char *filePath, uint32_t accessMode, uint32_t createMode) {
	char *diskPath = getDevicePath(filePath);
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(diskPath, &windowsPath[0], MAX_PATH_LEN);
	freeDevicePath(diskPath);

	HANDLE file = CreateFileW(
		&windowsPath[0],
		accessMode,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		nullptr,
		createMode,
		FILE_ATTRIBUTE_NORMAL,
		nullptr);

	return file;
}
#else
FILE *DirectoryDevice::openFile(const char *filePath, const char *modeString) {
	char *diskPath = getDevicePath(filePath);
	FILE *file = fopen(diskPath, modeString);
	freeDevicePath(diskPath);
	return file;
}
#endif

char *DirectoryDevice::getDevicePath(const char *filePath) {
	uint32_t diskPathLen = static_cast<uint32_t>(_pathLen + strlen(filePath) + 1);
	char *diskPath = reinterpret_cast<char*>(_alloc->alloc(_alloc->allocator, sizeof(char) * diskPathLen, alignof(char)));
	strcpy(diskPath, _devicePath);
	strcpy(diskPath + _pathLen, filePath);

	// replace forward slashes with backslashes on windows
#ifdef _WIN32
	for (uint32_t i = 0; i < diskPathLen; ++i) {
		if (diskPath[i] == '/')
			diskPath[i] = '\\';
	}
#endif

	return diskPath;
}

void DirectoryDevice::freeDevicePath(char *path) {
	_alloc->free(_alloc->allocator, path);
}

bool DirectoryDevice::fileExists(void *device, const char *filePath) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	char *diskPath = dev->getDevicePath(filePath);

#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(diskPath, &windowsPath[0], MAX_PATH_LEN);
	dev->freeDevicePath(diskPath);

	DWORD result = GetFileAttributesW(&windowsPath[0]);

	return result != INVALID_FILE_ATTRIBUTES && !(result & FILE_ATTRIBUTE_DIRECTORY);
#else
	struct stat statInfo;
	int result = stat(diskPath, &statInfo);

	dev->freeDevicePath(diskPath);
	return result == 0 && S_ISREG(statInfo.st_mode);
#endif
}

size_t DirectoryDevice::fileSize(void *device, const char *filePath, ErrorCode *outError) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	size_t size = 0;

#ifdef _WIN32
	HANDLE file = dev->openFile(filePath, GENERIC_READ, OPEN_EXISTING);

	if (file) {
		LARGE_INTEGER result;
		if(!GetFileSizeEx(file, &result)) {
			printf("error code %lu\n", GetLastError());
		} else {
			size = result.QuadPart;
		}
		CloseHandle(file);
	} else {
		*outError = convertError(GetLastError());
	}
#else
	char *diskPath = dev->getDevicePath(filePath);
	struct stat statInfo;
	int result = stat(diskPath, &statInfo);
	dev->freeDevicePath(diskPath);

	if (result == 0 && S_ISREG(statInfo.st_mode)) {
		*outError = LFS_OK;
		size = statInfo.st_size;
	} else if (result != 0) {
		*outError = convertError(errno);
	} else {
	   *outError = LFS_UNSUPPORTED;
	}
#endif
	return size;
}

size_t DirectoryDevice::readFile(void *device, const char *filePath, Allocator *alloc, void **buffer, bool nullTerminate, ErrorCode *outError) {
	size_t bytesRead = 0;
	DirectoryDevice *dir = static_cast<DirectoryDevice*>(device);
#ifdef _WIN32
	HANDLE file = dir->openFile(filePath, GENERIC_READ, OPEN_EXISTING);

	if (file) {
		LARGE_INTEGER result;
		GetFileSizeEx(file, &result);
		size_t fileSize = result.QuadPart;

		if (fileSize) {
			*buffer = alloc->alloc(alloc->allocator, fileSize + (nullTerminate ? 1 : 0), 1);

			DWORD bytesReadTemp = 0;
			if (!ReadFile(file, *buffer, (DWORD)fileSize, &bytesReadTemp, nullptr)) {
				*outError = convertError(GetLastError());
			} else if (nullTerminate) {
				(*(char**)buffer)[bytesRead] = 0;
			}

			bytesRead = bytesReadTemp;
		}

		CloseHandle(file);
	} else {
		*outError = LFS_NOT_FOUND;
	}
#else
	FILE *file = dir->openFile(filePath, "rb");

	if (file) {
		size_t fileSize = 0;
		if (fseek(file, 0L, SEEK_END) == 0) {
			fileSize = ftell(file);
		}

		if (fileSize && fseek(file, 0L, SEEK_SET) == 0) {
			*buffer = alloc->alloc(alloc->allocator, fileSize + (nullTerminate ? 1 : 0), 1);
			if (*buffer) {
				bytesRead = fread(*buffer, 1, fileSize, file);

				if (nullTerminate) {
					(*(char**)buffer)[bytesRead] = 0;
				}
			}
		}

		*outError = ferror(file) ? LFS_GENERIC_ERROR : LFS_OK;

		fclose(file);
	} else {
		*outError = LFS_NOT_FOUND;
	}
#endif
	return bytesRead;
}

size_t DirectoryDevice::writeFile(void *device, const char *filePath, void *buffer, size_t bytesToWrite, bool append, ErrorCode *outError) {
	size_t bytesWritten = 0;
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);

#ifdef _WIN32
	HANDLE file = dev->openFile(filePath, GENERIC_WRITE, append ? OPEN_ALWAYS : CREATE_ALWAYS);

	if (file) {
		if (append) {
			if (SetFilePointer(file, 0, nullptr, FILE_END) == INVALID_SET_FILE_POINTER) {
				*outError = LFS_GENERIC_ERROR;
				CloseHandle(file);
				return bytesWritten;
			}
		}

		DWORD temp = 0;
		if (!WriteFile(file, buffer, (DWORD)bytesToWrite, &temp, nullptr)) {
				*outError = LFS_GENERIC_ERROR;
		} else {
			bytesWritten = temp;
		}
	} else {
		*outError = convertError(GetLastError());
	}

	CloseHandle(file);
#else
	FILE *file = dev->openFile(filePath, append ? "ab" : "wb");

	if (file) {
		bytesWritten = fwrite(buffer, 1, bytesToWrite, file);
		*outError = ferror(file) ? LFS_GENERIC_ERROR : LFS_OK;
		fclose(file);
	} else {
		*outError = LFS_PERMISSIONS_ERROR;
	}
#endif
	return bytesWritten;
}

ErrorCode DirectoryDevice::deleteFile(void *device, const char *filePath) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	char *diskPath = dev->getDevicePath(filePath);

	ErrorCode resultCode = LFS_OK;
#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(diskPath, &windowsPath[0], MAX_PATH_LEN);

	if (!DeleteFileW(&windowsPath[0])) {
		resultCode = convertError(GetLastError());
	}
#else
	if (unlink(diskPath) != 0) {
		resultCode = convertError(errno);
	}
#endif

	dev->freeDevicePath(diskPath);
	return resultCode;
}

ErrorCode DirectoryDevice::createDir(void *device, const char *path) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	char *diskPath = dev->getDevicePath(path);

	ErrorCode resultCode = LFS_OK;
#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	widen(diskPath, &windowsPath[0], MAX_PATH_LEN);

	if (!CreateDirectoryW(&windowsPath[0], nullptr)) {
		resultCode = convertError(GetLastError());
	}
#else
	int result = mkdir(diskPath, DEFFILEMODE | S_IXUSR | S_IXGRP | S_IRWXO);

	if (result != 0) {
		resultCode = convertError(errno);
	}
#endif

	dev->freeDevicePath(diskPath);
	return resultCode;
}

ErrorCode DirectoryDevice::deleteDir(void *device, const char *path) {
	DirectoryDevice *dev = static_cast<DirectoryDevice*>(device);
	char *diskPath = dev->getDevicePath(path);

	ErrorCode resultCode = LFS_OK;

#ifdef _WIN32
	WCHAR windowsPath[MAX_PATH_LEN];
	int len = widen(diskPath, &windowsPath[0], MAX_PATH_LEN - 1); // XXX: ensure one space for double-null
	windowsPath[len] = 0;

	// just use the shell API to delete the directory.
	// requires path to be double null-terminated.
	// https://msdn.microsoft.com/en-us/library/windows/desktop/bb762164(v=vs.85).aspx
	SHFILEOPSTRUCTW shOp;
	shOp.hwnd = nullptr;
	shOp.wFunc = FO_DELETE;
	shOp.pFrom = &windowsPath[0];
	shOp.pTo = nullptr;
	shOp.fFlags = FOF_NO_UI;
	shOp.fAnyOperationsAborted = FALSE;
	shOp.hNameMappings = nullptr;
	shOp.lpszProgressTitle = nullptr;

	int result = SHFileOperationW(&shOp);

	switch (result) {
	case 0:
		break;
	case 0x7C: // DE_INVALIDFILES
		resultCode = LFS_NOT_FOUND;
		break;
	case 0x78: // DE_ACCESSDENIEDSRC
	case 0x86: // DE_SRC_IS_CDROM
	case 0x87: // DE_SRC_IS_DVD
		resultCode = LFS_PERMISSIONS_ERROR;
		break;
	default:
		resultCode = LFS_GENERIC_ERROR;
		break;
	};
#else
	FTS *fts = nullptr;
	char *fileList[] = {diskPath, nullptr};
	bool error = false;

	if ((fts = fts_open(fileList, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
		FTSENT *ent = fts_read(fts);
		while (!error && ent) {
			switch (ent->fts_info) {
			// ignore directories until post-traversal (FTS_DP)
			case FTS_D:
				break;

			// normal stuff we want to delete
			case FTS_DEFAULT:
			case FTS_DP:
			case FTS_F:
			case FTS_SL:
			case FTS_SLNONE:
				if (remove(ent->fts_accpath) == -1) {
					error = true;
				}
				break;

			// shouldn't ever hit these
			case FTS_DC:
			case FTS_DOT:
			case FTS_NSOK:
				break;

			// errors
			case FTS_NS:
			case FTS_DNR:
			case FTS_ERR:
				error = true;
				errno = ent->fts_errno;
				break;
			};

			if (!error)
				ent = fts_read(fts);
		}

		error = error || errno != 0;
		fts_close(fts);
	}

	if (error) {
		resultCode = convertError(errno);
	}
#endif

	dev->freeDevicePath(diskPath);
	return resultCode;
}
<|endoftext|>


<commit_before>#include <iostream>

void SetAliEnSettings()
{
   // Routine to load settings from an AliEn environment file.

   ifstream fileIn;
   fileIn.open(Form("%s/gclient_env_%d", gSystem->TempDirectory(), gSystem->GetUid()));
   if (gDebug>0) {printf("P010_TAlien.C: parsing %s/gclient_env_$UID\n", gSystem->TempDirectory());}
   TString lineS,tmp;
   char line[4096];

   while (fileIn.good()){
      fileIn.getline(line,4096,'\n');
      lineS = line;
      if (lineS.IsNull()) continue;
      if (lineS.Contains("export ")) {
         lineS.ReplaceAll("export ","");

         TObjArray* array = lineS.Tokenize("=");

         if (array->GetEntries() == 2) {
            TObjString *strVar = (TObjString *) array->At(0);
            TObjString *strVal = (TObjString *) array->At(1);

            if ((strVar)&&(strVal)) {
               tmp = strVal->GetString();
               tmp.ReplaceAll("\"","");
               tmp.ReplaceAll("$LD_LIBRARY_PATH",gSystem->Getenv("LD_LIBRARY_PATH"));
               tmp.ReplaceAll("$DYLD_LIBRARY_PATH",gSystem->Getenv("DYLD_LIBRARY_PATH"));
               tmp.ReplaceAll(" ","");
               gSystem->Unsetenv(strVar->GetString());
               gSystem->Setenv(strVar->GetString(), tmp);
               if (gDebug>0) {
                  Info("P010_TAlien", "setting environment %s=\"%s\"", strVar->GetString().Data(), tmp.Data());
               }
               if (!strVar->GetString().CompareTo("GCLIENT_SERVER_LIST")) {
                  gSystem->Unsetenv("alien_API_SERVER_LIST");
                  gSystem->Setenv("alien_API_SERVER_LIST", tmp);
               }
            }
            if (array) {
               delete array;
               array = 0 ;
            }
         } else {
            // parse the MONA_ stuff
            TObjArray* array = lineS.Tokenize("\" ");
            TString key="";
            TString val="";
            for (int i=0; i< array->GetEntries(); i++) {
               if ( ((TObjString*) array->At(i))->GetString().Contains("=")) {
                  if (key.Length() && val.Length()) {
                     val.Resize(val.Length()-1);
                     if (gDebug>0) {
                        Info("P010_TAlien", "setting environment %s=\"%s\"", key.Data(), val.Data());
                     }
                     gSystem->Unsetenv(key);
                     gSystem->Setenv(key, val);
                     key="";
                     val="";
                  }
                  key = ((TObjString*) array->At(i))->GetString();
                  key.ReplaceAll("=","");
               } else {
                  val+=((TObjString*) array->At(i))->GetString();
                  val+=" ";
               }
            }
            if (key.Length() && val.Length()) {
               if (gDebug>0) {
                  Info("P010_TAlien", "setting environment %s=\"%s\"", key.Data(), val.Data());
               }
               gSystem->Unsetenv(key);
               gSystem->Setenv(key, val);
            }
         }
      }
   }
}

void P010_TAlien()
{
   TString configfeatures = gROOT->GetConfigFeatures();
   TString ralienpath = gSystem->Getenv("ROOTSYS");
   ralienpath += "/lib/"; ralienpath += "libRAliEn.so";

   // only if ROOT was compiled with enable-alien we do library setup and configure a handler
   if ((!gSystem->AccessPathName(ralienpath)) || (configfeatures.contains("alien"))) {
      // you can enforce
      if ((!gSystem->Getenv("GBBOX_ENVFILE")) ||
          ( gSystem->Getenv("ALIEN_SOURCE_GCLIENT_ENV")) ||
          (!gSystem->Getenv("ALIEN_SKIP_GCLIENT_ENV")) ) {
       SetAliEnSettings();
      }

      if ( ((gSystem->Load("libgapiUI.so")>=0) && (gSystem->Load("libRAliEn.so")>=0)))  {
         gPluginMgr->AddHandler("TGrid", "^alien", "TAlien",
                                "RAliEn", "TAlien(const char*,const char*,const char*,const char*)");
      } else {
         Error("P010_TAlien","Please fix your loader path environment variable to be able to load libRAliEn.so");
      }
  }
}
<commit_msg>Fix typo.<commit_after>#include <iostream>

void SetAliEnSettings()
{
   // Routine to load settings from an AliEn environment file.

   ifstream fileIn;
   fileIn.open(Form("%s/gclient_env_%d", gSystem->TempDirectory(), gSystem->GetUid()));
   if (gDebug>0) {printf("P010_TAlien.C: parsing %s/gclient_env_$UID\n", gSystem->TempDirectory());}
   TString lineS,tmp;
   char line[4096];

   while (fileIn.good()){
      fileIn.getline(line,4096,'\n');
      lineS = line;
      if (lineS.IsNull()) continue;
      if (lineS.Contains("export ")) {
         lineS.ReplaceAll("export ","");

         TObjArray* array = lineS.Tokenize("=");

         if (array->GetEntries() == 2) {
            TObjString *strVar = (TObjString *) array->At(0);
            TObjString *strVal = (TObjString *) array->At(1);

            if ((strVar)&&(strVal)) {
               tmp = strVal->GetString();
               tmp.ReplaceAll("\"","");
               tmp.ReplaceAll("$LD_LIBRARY_PATH",gSystem->Getenv("LD_LIBRARY_PATH"));
               tmp.ReplaceAll("$DYLD_LIBRARY_PATH",gSystem->Getenv("DYLD_LIBRARY_PATH"));
               tmp.ReplaceAll(" ","");
               gSystem->Unsetenv(strVar->GetString());
               gSystem->Setenv(strVar->GetString(), tmp);
               if (gDebug>0) {
                  Info("P010_TAlien", "setting environment %s=\"%s\"", strVar->GetString().Data(), tmp.Data());
               }
               if (!strVar->GetString().CompareTo("GCLIENT_SERVER_LIST")) {
                  gSystem->Unsetenv("alien_API_SERVER_LIST");
                  gSystem->Setenv("alien_API_SERVER_LIST", tmp);
               }
            }
            if (array) {
               delete array;
               array = 0 ;
            }
         } else {
            // parse the MONA_ stuff
            TObjArray* array = lineS.Tokenize("\" ");
            TString key="";
            TString val="";
            for (int i=0; i< array->GetEntries(); i++) {
               if ( ((TObjString*) array->At(i))->GetString().Contains("=")) {
                  if (key.Length() && val.Length()) {
                     val.Resize(val.Length()-1);
                     if (gDebug>0) {
                        Info("P010_TAlien", "setting environment %s=\"%s\"", key.Data(), val.Data());
                     }
                     gSystem->Unsetenv(key);
                     gSystem->Setenv(key, val);
                     key="";
                     val="";
                  }
                  key = ((TObjString*) array->At(i))->GetString();
                  key.ReplaceAll("=","");
               } else {
                  val+=((TObjString*) array->At(i))->GetString();
                  val+=" ";
               }
            }
            if (key.Length() && val.Length()) {
               if (gDebug>0) {
                  Info("P010_TAlien", "setting environment %s=\"%s\"", key.Data(), val.Data());
               }
               gSystem->Unsetenv(key);
               gSystem->Setenv(key, val);
            }
         }
      }
   }
}

void P010_TAlien()
{
   TString configfeatures = gROOT->GetConfigFeatures();
   TString ralienpath = gSystem->Getenv("ROOTSYS");
   ralienpath += "/lib/"; ralienpath += "libRAliEn.so";

   // only if ROOT was compiled with enable-alien we do library setup and configure a handler
   if ((!gSystem->AccessPathName(ralienpath)) || (configfeatures.Contains("alien"))) {
      // you can enforce
      if ((!gSystem->Getenv("GBBOX_ENVFILE")) ||
          ( gSystem->Getenv("ALIEN_SOURCE_GCLIENT_ENV")) ||
          (!gSystem->Getenv("ALIEN_SKIP_GCLIENT_ENV")) ) {
       SetAliEnSettings();
      }

      if ( ((gSystem->Load("libgapiUI.so")>=0) && (gSystem->Load("libRAliEn.so")>=0)))  {
         gPluginMgr->AddHandler("TGrid", "^alien", "TAlien",
                                "RAliEn", "TAlien(const char*,const char*,const char*,const char*)");
      } else {
         Error("P010_TAlien","Please fix your loader path environment variable to be able to load libRAliEn.so");
      }
  }
}
<|endoftext|>


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

#include "content/public/browser/browser_main_runner.h"

#include "base/allocator/allocator_shim.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/notification_service_impl.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
#include "ui/base/ime/input_method_initializer.h"

#if defined(OS_WIN)
#include "base/win/metro.h"
#include "base/win/windows_version.h"
#include "ui/base/win/scoped_ole_initializer.h"
#endif

bool g_exited_main_message_loop = false;

namespace content {

class BrowserMainRunnerImpl : public BrowserMainRunner {
 public:
  BrowserMainRunnerImpl()
      : is_initialized_(false),
        is_shutdown_(false),
        created_threads_(false) {
  }

  virtual ~BrowserMainRunnerImpl() {
    if (is_initialized_ && !is_shutdown_)
      Shutdown();
  }

  virtual int Initialize(const MainFunctionParams& parameters)
      OVERRIDE {
    TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize")
    is_initialized_ = true;

#if defined(OS_WIN)
    if (parameters.command_line.HasSwitch(
            switches::kEnableTextServicesFramework)) {
      base::win::SetForceToUseTSF();
    } else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
      // When "Extend support of advanced text services to all programs"
      // (a.k.a. Cicero Unaware Application Support; CUAS) is enabled on
      // Windows XP and handwriting modules shipped with Office 2003 are
      // installed, "penjpn.dll" and "skchui.dll" will be loaded and then crash
      // unless a user installs Office 2003 SP3. To prevent these modules from
      // being loaded, disable TSF entirely. crbug/160914.
      // TODO(yukawa): Add a high-level wrapper for this instead of calling
      // Win32 API here directly.
      ImmDisableTextFrameService(static_cast<DWORD>(-1));
    }
#endif  // OS_WIN

    base::StatisticsRecorder::Initialize();

    notification_service_.reset(new NotificationServiceImpl);

#if defined(OS_WIN)
    // Ole must be initialized before starting message pump, so that TSF
    // (Text Services Framework) module can interact with the message pump
    // on Windows 8 Metro mode.
    ole_initializer_.reset(new ui::ScopedOleInitializer);
#endif  // OS_WIN

    main_loop_.reset(new BrowserMainLoop(parameters));

    main_loop_->Init();

    main_loop_->EarlyInitialization();

    // Must happen before we try to use a message loop or display any UI.
    main_loop_->InitializeToolkit();

    main_loop_->MainMessageLoopStart();

    // WARNING: If we get a WM_ENDSESSION, objects created on the stack here
    // are NOT deleted. If you need something to run during WM_ENDSESSION add it
    // to browser_shutdown::Shutdown or BrowserProcess::EndSession.

#if defined(OS_WIN) && !defined(NO_TCMALLOC)
    // When linking shared libraries, NO_TCMALLOC is defined, and dynamic
    // allocator selection is not supported.

    // Make this call before going multithreaded, or spawning any subprocesses.
    base::allocator::SetupSubprocessAllocator();
#endif
    ui::InitializeInputMethod();

    main_loop_->CreateThreads();
    int result_code = main_loop_->GetResultCode();
    if (result_code > 0)
      return result_code;
    created_threads_ = true;

    // Return -1 to indicate no early termination.
    return -1;
  }

  virtual int Run() OVERRIDE {
    DCHECK(is_initialized_);
    DCHECK(!is_shutdown_);
    main_loop_->RunMainMessageLoopParts();
    return main_loop_->GetResultCode();
  }

  virtual void Shutdown() OVERRIDE {
    DCHECK(is_initialized_);
    DCHECK(!is_shutdown_);
    g_exited_main_message_loop = true;

    if (created_threads_)
      main_loop_->ShutdownThreadsAndCleanUp();

    ui::ShutdownInputMethod();
#if defined(OS_WIN)
    ole_initializer_.reset(NULL);
#endif

    main_loop_.reset(NULL);

    notification_service_.reset(NULL);

    is_shutdown_ = true;
  }

 protected:
  // True if the runner has been initialized.
  bool is_initialized_;

  // True if the runner has been shut down.
  bool is_shutdown_;

  // True if the non-UI threads were created.
  bool created_threads_;

  scoped_ptr<NotificationServiceImpl> notification_service_;
  scoped_ptr<BrowserMainLoop> main_loop_;
#if defined(OS_WIN)
  scoped_ptr<ui::ScopedOleInitializer> ole_initializer_;
#endif

  DISALLOW_COPY_AND_ASSIGN(BrowserMainRunnerImpl);
};

// static
BrowserMainRunner* BrowserMainRunner::Create() {
  return new BrowserMainRunnerImpl();
}

}  // namespace content
<commit_msg>Fix --wait-for-debugger.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/public/browser/browser_main_runner.h"

#include "base/allocator/allocator_shim.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/notification_service_impl.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
#include "ui/base/ime/input_method_initializer.h"

#if defined(OS_WIN)
#include "base/win/metro.h"
#include "base/win/windows_version.h"
#include "ui/base/win/scoped_ole_initializer.h"
#endif

bool g_exited_main_message_loop = false;

namespace content {

class BrowserMainRunnerImpl : public BrowserMainRunner {
 public:
  BrowserMainRunnerImpl()
      : is_initialized_(false),
        is_shutdown_(false),
        created_threads_(false) {
  }

  virtual ~BrowserMainRunnerImpl() {
    if (is_initialized_ && !is_shutdown_)
      Shutdown();
  }

  virtual int Initialize(const MainFunctionParams& parameters)
      OVERRIDE {
    TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize")
    is_initialized_ = true;

#if !defined(OS_IOS)
  if (parameters.command_line.HasSwitch(switches::kWaitForDebugger))
    base::debug::WaitForDebugger(60, true);
#endif

#if defined(OS_WIN)
    if (parameters.command_line.HasSwitch(
            switches::kEnableTextServicesFramework)) {
      base::win::SetForceToUseTSF();
    } else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
      // When "Extend support of advanced text services to all programs"
      // (a.k.a. Cicero Unaware Application Support; CUAS) is enabled on
      // Windows XP and handwriting modules shipped with Office 2003 are
      // installed, "penjpn.dll" and "skchui.dll" will be loaded and then crash
      // unless a user installs Office 2003 SP3. To prevent these modules from
      // being loaded, disable TSF entirely. crbug/160914.
      // TODO(yukawa): Add a high-level wrapper for this instead of calling
      // Win32 API here directly.
      ImmDisableTextFrameService(static_cast<DWORD>(-1));
    }
#endif  // OS_WIN

    base::StatisticsRecorder::Initialize();

    notification_service_.reset(new NotificationServiceImpl);

#if defined(OS_WIN)
    // Ole must be initialized before starting message pump, so that TSF
    // (Text Services Framework) module can interact with the message pump
    // on Windows 8 Metro mode.
    ole_initializer_.reset(new ui::ScopedOleInitializer);
#endif  // OS_WIN

    main_loop_.reset(new BrowserMainLoop(parameters));

    main_loop_->Init();

    main_loop_->EarlyInitialization();

    // Must happen before we try to use a message loop or display any UI.
    main_loop_->InitializeToolkit();

    main_loop_->MainMessageLoopStart();

    // WARNING: If we get a WM_ENDSESSION, objects created on the stack here
    // are NOT deleted. If you need something to run during WM_ENDSESSION add it
    // to browser_shutdown::Shutdown or BrowserProcess::EndSession.

#if defined(OS_WIN) && !defined(NO_TCMALLOC)
    // When linking shared libraries, NO_TCMALLOC is defined, and dynamic
    // allocator selection is not supported.

    // Make this call before going multithreaded, or spawning any subprocesses.
    base::allocator::SetupSubprocessAllocator();
#endif
    ui::InitializeInputMethod();

    main_loop_->CreateThreads();
    int result_code = main_loop_->GetResultCode();
    if (result_code > 0)
      return result_code;
    created_threads_ = true;

    // Return -1 to indicate no early termination.
    return -1;
  }

  virtual int Run() OVERRIDE {
    DCHECK(is_initialized_);
    DCHECK(!is_shutdown_);
    main_loop_->RunMainMessageLoopParts();
    return main_loop_->GetResultCode();
  }

  virtual void Shutdown() OVERRIDE {
    DCHECK(is_initialized_);
    DCHECK(!is_shutdown_);
    g_exited_main_message_loop = true;

    if (created_threads_)
      main_loop_->ShutdownThreadsAndCleanUp();

    ui::ShutdownInputMethod();
#if defined(OS_WIN)
    ole_initializer_.reset(NULL);
#endif

    main_loop_.reset(NULL);

    notification_service_.reset(NULL);

    is_shutdown_ = true;
  }

 protected:
  // True if the runner has been initialized.
  bool is_initialized_;

  // True if the runner has been shut down.
  bool is_shutdown_;

  // True if the non-UI threads were created.
  bool created_threads_;

  scoped_ptr<NotificationServiceImpl> notification_service_;
  scoped_ptr<BrowserMainLoop> main_loop_;
#if defined(OS_WIN)
  scoped_ptr<ui::ScopedOleInitializer> ole_initializer_;
#endif

  DISALLOW_COPY_AND_ASSIGN(BrowserMainRunnerImpl);
};

// static
BrowserMainRunner* BrowserMainRunner::Create() {
  return new BrowserMainRunnerImpl();
}

}  // namespace content
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE RDOTriangularTest
#include <boost/test/included/unit_test.hpp>
// ----------------------------------------------------------------------- SYNOPSIS
#include "simulator/runtime/rdo_random_distribution.h"

BOOST_AUTO_TEST_CASE(RDOTriangularTest)
{

}<commit_msg>* reverted changes from rev.4925<commit_after>/*!
  \copyright (c) RDO-Team, 2011
  \file      main.cpp
  \author      (rdo@rk9.bmstu.ru)
  \authors     (impus@hotbox.ru)
  \date      12.09.2011
  \brief
  \indent    4T
*/

// ---------------------------------------------------------------------------- PCH
// ----------------------------------------------------------------------- INCLUDES
#include "stdafx.h"
#define BOOST_TEST_MODULE RDOTriangularTest
#include <boost/test/included/unit_test.hpp>
// ----------------------------------------------------------------------- SYNOPSIS
#include "simulator/runtime/rdo_random_distribution.h"
// --------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(RDOTriangularTest)
{

}

<|endoftext|>


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

#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <mraa.h>
#include <string>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace std;

static const char *dev_name = "/dev/lepton";
void sig_handler(int signum);
static sig_atomic_t volatile isrunning = 1;
uint32_t frame_counter = 0;
#define exitIfMRAAError(x) exitIfMRAAError_internal(x, __FILE__, __LINE__)

static void exitIfMRAAError_internal(mraa_result_t result, const char *filename,
		unsigned int linenum) {
	if (__builtin_expect(result != MRAA_SUCCESS, 0)) {
		const char *errMsg = NULL;
		switch (result) {
		case MRAA_ERROR_FEATURE_NOT_IMPLEMENTED:
			errMsg = "MRAA_ERROR_FEATURE_NOT_IMPLEMENTED";
			break;
		case MRAA_ERROR_FEATURE_NOT_SUPPORTED:
			errMsg = "MRAA_ERROR_FEATURE_NOT_SUPPORTED";
			break;
		case MRAA_ERROR_INVALID_VERBOSITY_LEVEL:
			errMsg = "MRAA_ERROR_INVALID_VERBOSITY_LEVEL";
			break;
		case MRAA_ERROR_INVALID_PARAMETER:
			errMsg = "MRAA_ERROR_INVALID_PARAMETER";
			break;
		case MRAA_ERROR_INVALID_HANDLE:
			errMsg = "MRAA_ERROR_INVALID_HANDLE";
			break;
		case MRAA_ERROR_NO_RESOURCES:
			errMsg = "MRAA_ERROR_NO_RESOURCES";
			break;
		case MRAA_ERROR_INVALID_RESOURCE:
			errMsg = "MRAA_ERROR_INVALID_RESOURCE";
			break;
		case MRAA_ERROR_INVALID_QUEUE_TYPE:
			errMsg = "MRAA_ERROR_INVALID_QUEUE_TYPE";
			break;
		case MRAA_ERROR_NO_DATA_AVAILABLE:
			errMsg = "MRAA_ERROR_NO_DATA_AVAILABLE";
			break;
		case MRAA_ERROR_INVALID_PLATFORM:
			errMsg = "MRAA_ERROR_INVALID_PLATFORM";
			break;
		case MRAA_ERROR_PLATFORM_NOT_INITIALISED:
			errMsg = "MRAA_ERROR_PLATFORM_NOT_INITIALISED";
			break;
		case MRAA_ERROR_PLATFORM_ALREADY_INITIALISED:
			errMsg = "MRAA_ERROR_PLATFORM_ALREADY_INITIALISED";
			break;
		case MRAA_ERROR_UNSPECIFIED:
			errMsg = "MRAA_ERROR_UNSPECIFIED";
			break;
		default:
			errMsg = "Completely unknown error in MRAA";
		}
		error_at_line(result, errno, filename, linenum, "Error %d in MRAA: %s",
				(int) result, errMsg);
	}
}

static int captureImage(uint16_t *image, mraa_gpio_context cs, int fd) {
	const int line_len = 164;
	int result, i = 0, retval = 0;
	uint8_t buff[line_len * 60];
	while (i < 60 && isrunning) {
		uint8_t *line = &buff[i * line_len];
		uint16_t *line16 = (uint16_t *) line;
		memset(line, 0, line_len);
		result = read(fd, line, line_len);
		if (__builtin_expect(result == -1, 0)) {
			error(0, errno, "Error reading from [%s]", dev_name);
			break;
		} else if (__builtin_expect(result != line_len, 0)) {
			error(0, errno, "Size did not match, read %d, expected %d",
					(int) result, line_len);
			break;
		}
		line[0] &= 0x0F;
		if (__builtin_expect(line[0] != 0x0F, 0)) {
			uint16_t lineNum = ntohs(line16[0]);
			if (__builtin_expect(i != lineNum, 0)) {
				printf("Unexpected line. Expected %d found %d\n", (int) i,
						(int) lineNum);
				break;
			}
			++i;
		}
	}
	retval = i - 60;
	if (__builtin_expect(retval, 0)) {
		return retval;
	}
	for (i = 0; i < 60; ++i) {
		uint8_t *line = &buff[i * line_len];
		memcpy(&image[i * 80], &line[4], 160);
	}

	return retval;
}

#define BOUNDARY "hfihuuhf782hf4278fh2h4f7842hfh87942h"

static const char boundary_end_str[] = "\r\n--" BOUNDARY "\r\n";

static int safe_write(int fd, uint8_t *ptr, ssize_t len) {
	for (ssize_t write_remaining = len, my_write = 0; write_remaining > 0;
			write_remaining -= my_write) {
		my_write = write(fd, ptr, write_remaining);
		if (__builtin_expect(-1 == my_write, 0)) {
			// Skip things like EAGAIN for now
			error(0, errno, "Error writing image data");
			return -1;
		}
		ptr = &ptr[my_write];
	}
	return len;
}

// image is still BigEndian when it gets here
static int printImg(uint16_t *image, int out_fd) {
	uint16_t min_v = (uint16_t) -1;
	uint16_t max_v = 0;
	for (int i = 0; i < 60; ++i) {
		uint16_t *line = &image[i * 80];
		for (int j = 0; j < 78/*80*/; ++j) {
			uint16_t v = line[j] = ntohs(line[j]);
			if (__builtin_expect(v > max_v, 0)) {
				max_v = v;
			}
			if (__builtin_expect(v < min_v, 0)) {
				min_v = v;
			}
		}
	}

	uint16_t scale = max_v - min_v;
	Mat grayScaleImage(60, 80, CV_8UC1);
	uint8_t *img_out = (uint8_t *) &grayScaleImage.data[0];
	for (int i = 0; i < 60; ++i) {
		const int idex = i * 80;
		uint16_t *line = &image[idex];
		uint8_t *line_out = &img_out[idex];
		for (int j = 0; j < 78/*80*/; ++j) {
			line_out[j] = (((line[j] - min_v) << 8) / scale) & 0xFF;
		}
		line_out[78] = line_out[79] = 0;
	}

	uint8_t strbuff[1024];

	std::vector<uchar> buff;
	try {
		if (!imencode(".jpeg", grayScaleImage, buff)) {
			error(0, 0, "Error writing jpeg image to buffer");
			return -1;
		}
	} catch (cv::Exception &ex) {
		std::cout << "Error writing image: " <<ex.what() << std::endl;
		return -1;
	}

	ssize_t out_str_len = snprintf((char *) strbuff, sizeof(strbuff),
			"Content-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n", buff.size());
	if (out_str_len < 0) {
		error(0, errno, "Error writing output header");
		return -1;
	}
	if (safe_write(out_fd, strbuff, out_str_len) < 0) {
		return -1;
	}
	if (safe_write(out_fd, buff.data(), buff.size()) < 0) {
		return -1;
	}
	if (safe_write(out_fd, (uint8_t *) boundary_end_str,
			sizeof(boundary_end_str) - 1) < 0) {
		return -1;
	}
	return 0;
}

int main(int argc, char **argv) {
	int fd;
	uint32_t frameNum = 0;
	uint16_t image[80 * 60];
	mraa_gpio_context cs;
	Size size(80, 60);

	socklen_t sin_size = sizeof(struct sockaddr_in);
	int socket_fd = socket(PF_INET, SOCK_STREAM, 0);
	struct sockaddr_in sin, their_sin;
	sin.sin_family = AF_INET;
	inet_aton("192.168.1.139", &sin.sin_addr);
	//sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = htons(8888);
	memset(&(sin.sin_zero), '\0', 8);
	if (-1
			== bind(socket_fd, (const struct sockaddr *) &sin,
					sizeof(sockaddr_in))) {
		error(-1, errno, "Error binding to 8888");
	}

	if (-1 == listen(socket_fd, 1)) {
		error(-1, errno, "Error listening");
	}

	signal(SIGINT, &sig_handler);
	cs = mraa_gpio_init(45);
	if (cs == NULL) {
		error(1, errno, "Error initializing cs on gpio10");
	}
	exitIfMRAAError(mraa_gpio_dir(cs, MRAA_GPIO_OUT));
	exitIfMRAAError(mraa_gpio_write(cs, 1)); // write CS`
	printf("Syncing with Lepton...\n");
	usleep(200000);
	fd = open(dev_name, O_RDONLY);
	if (fd == -1) {
		error(-1, errno, "Error opening %s", dev_name);
	}

	printf("Activating Lepton...\n");
	int out_fd = -1;
	while (isrunning) {
		if (-1 == out_fd || captureImage(image, cs, fd) < 0) {
			exitIfMRAAError(mraa_gpio_write(cs, 1)); // High to de-select
			while (-1 == out_fd && isrunning) {
				out_fd = accept(socket_fd, (struct sockaddr *) &their_sin,
						&sin_size);
				if (-1 == out_fd) {
					error(0, errno, "Error accepting socket, retrying");
				} else {
					char out_buffer[4096] = { 0 };
					snprintf(out_buffer, sizeof(out_buffer),
							"HTTP/1.0 20 OK\r\n"
									"Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n"
							"\r\n--" BOUNDARY "\r\n");
					int len = strlen(out_buffer);
					if (len != write(out_fd, out_buffer, len)) {
						error(0, 0, "Error writing bytes");
						close(out_fd);
						out_fd = -1;
					}
				}
			};
			frameNum = 0;
			// Actually only needs to be ~185ms
			usleep(200000);
			exitIfMRAAError(mraa_gpio_write(cs, 0)); // Select device
		} else {
			if (frameNum++ % 3 == 0) {
				if (-1 == printImg(image, out_fd)) {
					error(0, 0, "Problem with socket, closing. %s", isrunning ? "" : "Also is done");
					close(out_fd);
					out_fd = -1;
				}
			}
		}
	}
	exitIfMRAAError(mraa_gpio_write(cs, 1)); // High to de-select
	exitIfMRAAError(mraa_gpio_close(cs));
	if (out_fd != -1) {
		close(out_fd);
	}
	close(fd);
	return 0;
}

void sig_handler(int signum) {
	if (signum == SIGINT)
		isrunning = 0;
}
<commit_msg>Remove specific IP address.<commit_after>/******************************************************************************
 * Copyright (c) 2016 Charles R. Allen
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 ******************************************************************************
 * lepton.cpp
 *
 *  Created on: Mar 7, 2016
 *      Author: Charles Allen
 */

#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <mraa.h>
#include <string>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace std;

static const char *dev_name = "/dev/lepton";
void sig_handler(int signum);
static sig_atomic_t volatile isrunning = 1;
uint32_t frame_counter = 0;
#define exitIfMRAAError(x) exitIfMRAAError_internal(x, __FILE__, __LINE__)

static void exitIfMRAAError_internal(mraa_result_t result, const char *filename,
		unsigned int linenum) {
	if (__builtin_expect(result != MRAA_SUCCESS, 0)) {
		const char *errMsg = NULL;
		switch (result) {
		case MRAA_ERROR_FEATURE_NOT_IMPLEMENTED:
			errMsg = "MRAA_ERROR_FEATURE_NOT_IMPLEMENTED";
			break;
		case MRAA_ERROR_FEATURE_NOT_SUPPORTED:
			errMsg = "MRAA_ERROR_FEATURE_NOT_SUPPORTED";
			break;
		case MRAA_ERROR_INVALID_VERBOSITY_LEVEL:
			errMsg = "MRAA_ERROR_INVALID_VERBOSITY_LEVEL";
			break;
		case MRAA_ERROR_INVALID_PARAMETER:
			errMsg = "MRAA_ERROR_INVALID_PARAMETER";
			break;
		case MRAA_ERROR_INVALID_HANDLE:
			errMsg = "MRAA_ERROR_INVALID_HANDLE";
			break;
		case MRAA_ERROR_NO_RESOURCES:
			errMsg = "MRAA_ERROR_NO_RESOURCES";
			break;
		case MRAA_ERROR_INVALID_RESOURCE:
			errMsg = "MRAA_ERROR_INVALID_RESOURCE";
			break;
		case MRAA_ERROR_INVALID_QUEUE_TYPE:
			errMsg = "MRAA_ERROR_INVALID_QUEUE_TYPE";
			break;
		case MRAA_ERROR_NO_DATA_AVAILABLE:
			errMsg = "MRAA_ERROR_NO_DATA_AVAILABLE";
			break;
		case MRAA_ERROR_INVALID_PLATFORM:
			errMsg = "MRAA_ERROR_INVALID_PLATFORM";
			break;
		case MRAA_ERROR_PLATFORM_NOT_INITIALISED:
			errMsg = "MRAA_ERROR_PLATFORM_NOT_INITIALISED";
			break;
		case MRAA_ERROR_PLATFORM_ALREADY_INITIALISED:
			errMsg = "MRAA_ERROR_PLATFORM_ALREADY_INITIALISED";
			break;
		case MRAA_ERROR_UNSPECIFIED:
			errMsg = "MRAA_ERROR_UNSPECIFIED";
			break;
		default:
			errMsg = "Completely unknown error in MRAA";
		}
		error_at_line(result, errno, filename, linenum, "Error %d in MRAA: %s",
				(int) result, errMsg);
	}
}

static int captureImage(uint16_t *image, mraa_gpio_context cs, int fd) {
	const int line_len = 164;
	int result, i = 0, retval = 0;
	uint8_t buff[line_len * 60];
	while (i < 60 && isrunning) {
		uint8_t *line = &buff[i * line_len];
		uint16_t *line16 = (uint16_t *) line;
		memset(line, 0, line_len);
		result = read(fd, line, line_len);
		if (__builtin_expect(result == -1, 0)) {
			error(0, errno, "Error reading from [%s]", dev_name);
			break;
		} else if (__builtin_expect(result != line_len, 0)) {
			error(0, errno, "Size did not match, read %d, expected %d",
					(int) result, line_len);
			break;
		}
		line[0] &= 0x0F;
		if (__builtin_expect(line[0] != 0x0F, 0)) {
			uint16_t lineNum = ntohs(line16[0]);
			if (__builtin_expect(i != lineNum, 0)) {
				printf("Unexpected line. Expected %d found %d\n", (int) i,
						(int) lineNum);
				break;
			}
			++i;
		}
	}
	retval = i - 60;
	if (__builtin_expect(retval, 0)) {
		return retval;
	}
	for (i = 0; i < 60; ++i) {
		uint8_t *line = &buff[i * line_len];
		memcpy(&image[i * 80], &line[4], 160);
	}

	return retval;
}

#define BOUNDARY "hfihuuhf782hf4278fh2h4f7842hfh87942h"

static const char boundary_end_str[] = "\r\n--" BOUNDARY "\r\n";

static int safe_write(int fd, uint8_t *ptr, ssize_t len) {
	for (ssize_t write_remaining = len, my_write = 0; write_remaining > 0;
			write_remaining -= my_write) {
		my_write = write(fd, ptr, write_remaining);
		if (__builtin_expect(-1 == my_write, 0)) {
			// Skip things like EAGAIN for now
			error(0, errno, "Error writing image data");
			return -1;
		}
		ptr = &ptr[my_write];
	}
	return len;
}

// image is still BigEndian when it gets here
static int printImg(uint16_t *image, int out_fd) {
	uint16_t min_v = (uint16_t) -1;
	uint16_t max_v = 0;
	for (int i = 0; i < 60; ++i) {
		uint16_t *line = &image[i * 80];
		for (int j = 0; j < 78/*80*/; ++j) {
			uint16_t v = line[j] = ntohs(line[j]);
			if (__builtin_expect(v > max_v, 0)) {
				max_v = v;
			}
			if (__builtin_expect(v < min_v, 0)) {
				min_v = v;
			}
		}
	}

	uint16_t scale = max_v - min_v;
	Mat grayScaleImage(60, 80, CV_8UC1);
	uint8_t *img_out = (uint8_t *) &grayScaleImage.data[0];
	for (int i = 0; i < 60; ++i) {
		const int idex = i * 80;
		uint16_t *line = &image[idex];
		uint8_t *line_out = &img_out[idex];
		for (int j = 0; j < 78/*80*/; ++j) {
			line_out[j] = (((line[j] - min_v) << 8) / scale) & 0xFF;
		}
		line_out[78] = line_out[79] = 0;
	}

	uint8_t strbuff[1024];

	std::vector<uchar> buff;
	try {
		if (!imencode(".jpeg", grayScaleImage, buff)) {
			error(0, 0, "Error writing jpeg image to buffer");
			return -1;
		}
	} catch (cv::Exception &ex) {
		std::cout << "Error writing image: " <<ex.what() << std::endl;
		return -1;
	}

	ssize_t out_str_len = snprintf((char *) strbuff, sizeof(strbuff),
			"Content-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n", buff.size());
	if (out_str_len < 0) {
		error(0, errno, "Error writing output header");
		return -1;
	}
	if (safe_write(out_fd, strbuff, out_str_len) < 0) {
		return -1;
	}
	if (safe_write(out_fd, buff.data(), buff.size()) < 0) {
		return -1;
	}
	if (safe_write(out_fd, (uint8_t *) boundary_end_str,
			sizeof(boundary_end_str) - 1) < 0) {
		return -1;
	}
	return 0;
}

int main(int argc, char **argv) {
	int fd;
	uint32_t frameNum = 0;
	uint16_t image[80 * 60];
	mraa_gpio_context cs;
	Size size(80, 60);

	socklen_t sin_size = sizeof(struct sockaddr_in);
	int socket_fd = socket(PF_INET, SOCK_STREAM, 0);
	struct sockaddr_in sin, their_sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = htons(8888);
	memset(&(sin.sin_zero), '\0', 8);
	if (-1
			== bind(socket_fd, (const struct sockaddr *) &sin,
					sizeof(sockaddr_in))) {
		error(-1, errno, "Error binding to 8888");
	}

	if (-1 == listen(socket_fd, 1)) {
		error(-1, errno, "Error listening");
	}

	signal(SIGINT, &sig_handler);
	cs = mraa_gpio_init(45);
	if (cs == NULL) {
		error(1, errno, "Error initializing cs on gpio10");
	}
	exitIfMRAAError(mraa_gpio_dir(cs, MRAA_GPIO_OUT));
	exitIfMRAAError(mraa_gpio_write(cs, 1)); // write CS`
	printf("Syncing with Lepton...\n");
	usleep(200000);
	fd = open(dev_name, O_RDONLY);
	if (fd == -1) {
		error(-1, errno, "Error opening %s", dev_name);
	}

	printf("Activating Lepton...\n");
	int out_fd = -1;
	while (isrunning) {
		if (-1 == out_fd || captureImage(image, cs, fd) < 0) {
			exitIfMRAAError(mraa_gpio_write(cs, 1)); // High to de-select
			while (-1 == out_fd && isrunning) {
				out_fd = accept(socket_fd, (struct sockaddr *) &their_sin,
						&sin_size);
				if (-1 == out_fd) {
					error(0, errno, "Error accepting socket, retrying");
				} else {
					char out_buffer[4096] = { 0 };
					snprintf(out_buffer, sizeof(out_buffer),
							"HTTP/1.0 20 OK\r\n"
									"Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n"
							"\r\n--" BOUNDARY "\r\n");
					int len = strlen(out_buffer);
					if (len != write(out_fd, out_buffer, len)) {
						error(0, 0, "Error writing bytes");
						close(out_fd);
						out_fd = -1;
					}
				}
			};
			frameNum = 0;
			// Actually only needs to be ~185ms
			usleep(200000);
			exitIfMRAAError(mraa_gpio_write(cs, 0)); // Select device
		} else {
			if (frameNum++ % 3 == 0) {
				if (-1 == printImg(image, out_fd)) {
					error(0, 0, "Problem with socket, closing. %s", isrunning ? "" : "Also is done");
					close(out_fd);
					out_fd = -1;
				}
			}
		}
	}
	exitIfMRAAError(mraa_gpio_write(cs, 1)); // High to de-select
	exitIfMRAAError(mraa_gpio_close(cs));
	if (out_fd != -1) {
		close(out_fd);
	}
	close(fd);
	return 0;
}

void sig_handler(int signum) {
	if (signum == SIGINT)
		isrunning = 0;
}
<|endoftext|>


<commit_before>// Copyright 2012 Google Inc.
//
// 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 "syzygy/agent/profiler/return_thunk_factory.h"

#include "syzygy/agent/profiler/scoped_last_error_keeper.h"

namespace {

// Static assembly function called by all thunks.  It ends up calling to
// ReturnThunkFactory::ThunkMain.
extern "C" void __declspec(naked) thunk_main_asm() {
  __asm {
    // Stash volatile registers.
    push eax
    push ecx
    push edx
    pushfd

    // Get the current cycle time.
    rdtsc
    push edx
    push eax

    // Calculate a pointer to the start of the thunk object as
    // the return address pushed by the caller, subtracting 5 (the
    // size of the E8 call instruction) to get a pointer to the
    // start of the thunk object.
    mov eax, DWORD PTR[esp + 0x18]
    sub eax, 5
    push eax

    call agent::client::ReturnThunkFactory::ThunkMain

    // Restore volatile registers, except eax.
    popfd
    pop edx
    pop ecx

    // We start with:
    //   EAX: real ret-address
    //   stack:
    //     pushed EAX
    //     ret-address to thunk
    //
    // We end with:
    //   EAX: pushed EAX
    //   stack:
    //     ret-address to thunk
    //     real ret-address
    xchg eax, DWORD PTR[esp + 0x4]
    xchg eax, DWORD PTR[esp]

    // Return to the thunk, which will in turn return to the real
    // return address.
    ret
  }
}

}  // namespace

namespace agent {
namespace client {

ReturnThunkFactory::ReturnThunkFactory(Delegate* delegate)
    : delegate_(delegate),
      first_free_thunk_(NULL) {
  DCHECK(delegate_ != NULL);
  AddPage();
}

ReturnThunkFactory::~ReturnThunkFactory() {
  // Walk to the head of the page list, then release to the tail.
  Page* current_page = PageFromThunk(first_free_thunk_);

  while (current_page->previous_page)
    current_page = current_page->previous_page;

  while (current_page->next_page) {
    Page* page_to_free = current_page;
    current_page = current_page->next_page;

    // Notify the delegate of the release. We do this before freeing the memory
    // to make sure we don't open a race where a new thread could sneak a stack
    // into the page allocation.
    delegate_->OnPageRemoved(page_to_free);

    ::VirtualFree(page_to_free, 0, MEM_RELEASE);
  }
}

ReturnThunkFactory::Thunk* ReturnThunkFactory::MakeThunk(RetAddr real_ret) {
  Thunk* thunk = first_free_thunk_;
  thunk->caller = real_ret;

  Page* current_page = PageFromThunk(first_free_thunk_);
  if (first_free_thunk_ != LastThunk(current_page)) {
    first_free_thunk_++;
  } else if (current_page->next_page) {
    first_free_thunk_ = &current_page->next_page->thunks[0];
  } else {
    AddPage();
  }

  return thunk;
}

void ReturnThunkFactory::AddPage() {
  Page* previous_page = PageFromThunk(first_free_thunk_);
  DCHECK(previous_page == NULL || previous_page->next_page == NULL);

  // TODO(joi): This may be consuming 64K of memory, in which case it would
  // be more efficient to reserve a larger block at a time if we think we
  // normally need more than 4K of thunks.
  Page* new_page = reinterpret_cast<Page*>(::VirtualAlloc(
      NULL, kPageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
  CHECK(new_page);
  new_page->previous_page = previous_page;
  new_page->next_page = NULL;
  new_page->factory = this;

  if (previous_page)
    previous_page->next_page = new_page;

  // Since thunks get reused a lot, we optimize a bit by filling in the
  // static part of all thunks when each page is allocated.
  for (size_t i= 0; i < kNumThunksPerPage; ++i) {
    Thunk* thunk = &new_page->thunks[i];
    thunk->call = 0xE8;  // call
    thunk->func_addr = reinterpret_cast<DWORD>(thunk_main_asm) -
        reinterpret_cast<DWORD>(&thunk->ret);
    thunk->ret = 0xC3;
  }

  first_free_thunk_ = &new_page->thunks[0];

  // Notify the delegate that the page has been allocated.
  delegate_->OnPageAdded(new_page);
}

// static
ReturnThunkFactory::Page* ReturnThunkFactory::PageFromThunk(Thunk* thunk) {
  return reinterpret_cast<Page*>(reinterpret_cast<DWORD>(thunk) & kPageMask);
}

// static
ReturnThunkFactory::Thunk* ReturnThunkFactory::LastThunk(Page* page) {
  return &page->thunks[kNumThunksPerPage - 1];
}

// static
RetAddr WINAPI ReturnThunkFactory::ThunkMain(Thunk* thunk, uint64 cycles) {
  DCHECK(*reinterpret_cast<BYTE*>(thunk) == 0xE8);

  ScopedLastErrorKeeper keep_last_error;

  ReturnThunkFactory* factory = PageFromThunk(thunk)->factory;
  factory->first_free_thunk_ = thunk;

  factory->delegate_->OnFunctionExit(thunk, cycles);

  return thunk->caller;
}

}  // namespace client
}  // namespace agent
<commit_msg>Tweak return thunk assembly.<commit_after>// Copyright 2012 Google Inc.
//
// 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 "syzygy/agent/profiler/return_thunk_factory.h"

#include "syzygy/agent/profiler/scoped_last_error_keeper.h"

namespace {

// Static assembly function called by all thunks.  It ends up calling to
// ReturnThunkFactory::ThunkMain.
extern "C" void __declspec(naked) thunk_main_asm() {
  __asm {
    // Stash volatile registers.
    push eax
    push edx

    // Get the current cycle time ASAP.
    rdtsc

    push ecx
    pushfd

    // Push the cycle time arg for the ThunkMain function.
    push edx
    push eax

    // Calculate a pointer to the start of the thunk object as
    // the return address pushed by the caller, subtracting 5 (the
    // size of the E8 call instruction) to get a pointer to the
    // start of the thunk object.
    mov eax, DWORD PTR[esp + 0x18]
    sub eax, 5
    push eax

    call agent::client::ReturnThunkFactory::ThunkMain

    // Restore volatile registers, except eax.
    popfd
    pop ecx
    pop edx

    // At this point we have:
    //   EAX: real ret-address
    //   stack:
    //     pushed EAX
    //     ret-address to thunk
    push eax
    mov eax, DWORD PTR[esp+4]

    // Return and discard the stored eax and discarded return address.
    ret 8
  }
}

}  // namespace

namespace agent {
namespace client {

ReturnThunkFactory::ReturnThunkFactory(Delegate* delegate)
    : delegate_(delegate),
      first_free_thunk_(NULL) {
  DCHECK(delegate_ != NULL);
  AddPage();
}

ReturnThunkFactory::~ReturnThunkFactory() {
  // Walk to the head of the page list, then release to the tail.
  Page* current_page = PageFromThunk(first_free_thunk_);

  while (current_page->previous_page)
    current_page = current_page->previous_page;

  while (current_page->next_page) {
    Page* page_to_free = current_page;
    current_page = current_page->next_page;

    // Notify the delegate of the release. We do this before freeing the memory
    // to make sure we don't open a race where a new thread could sneak a stack
    // into the page allocation.
    delegate_->OnPageRemoved(page_to_free);

    ::VirtualFree(page_to_free, 0, MEM_RELEASE);
  }
}

ReturnThunkFactory::Thunk* ReturnThunkFactory::MakeThunk(RetAddr real_ret) {
  Thunk* thunk = first_free_thunk_;
  thunk->caller = real_ret;

  Page* current_page = PageFromThunk(first_free_thunk_);
  if (first_free_thunk_ != LastThunk(current_page)) {
    first_free_thunk_++;
  } else if (current_page->next_page) {
    first_free_thunk_ = &current_page->next_page->thunks[0];
  } else {
    AddPage();
  }

  return thunk;
}

void ReturnThunkFactory::AddPage() {
  Page* previous_page = PageFromThunk(first_free_thunk_);
  DCHECK(previous_page == NULL || previous_page->next_page == NULL);

  // TODO(joi): This may be consuming 64K of memory, in which case it would
  // be more efficient to reserve a larger block at a time if we think we
  // normally need more than 4K of thunks.
  Page* new_page = reinterpret_cast<Page*>(::VirtualAlloc(
      NULL, kPageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
  CHECK(new_page);
  new_page->previous_page = previous_page;
  new_page->next_page = NULL;
  new_page->factory = this;

  if (previous_page)
    previous_page->next_page = new_page;

  // Since thunks get reused a lot, we optimize a bit by filling in the
  // static part of all thunks when each page is allocated.
  for (size_t i= 0; i < kNumThunksPerPage; ++i) {
    Thunk* thunk = &new_page->thunks[i];
    thunk->call = 0xE8;  // call
    thunk->func_addr = reinterpret_cast<DWORD>(thunk_main_asm) -
        reinterpret_cast<DWORD>(&thunk->caller);
  }

  first_free_thunk_ = &new_page->thunks[0];

  // Notify the delegate that the page has been allocated.
  delegate_->OnPageAdded(new_page);
}

// static
ReturnThunkFactory::Page* ReturnThunkFactory::PageFromThunk(Thunk* thunk) {
  return reinterpret_cast<Page*>(reinterpret_cast<DWORD>(thunk) & kPageMask);
}

// static
ReturnThunkFactory::Thunk* ReturnThunkFactory::LastThunk(Page* page) {
  return &page->thunks[kNumThunksPerPage - 1];
}

// static
RetAddr WINAPI ReturnThunkFactory::ThunkMain(Thunk* thunk, uint64 cycles) {
  DCHECK(*reinterpret_cast<BYTE*>(thunk) == 0xE8);

  ScopedLastErrorKeeper keep_last_error;

  ReturnThunkFactory* factory = PageFromThunk(thunk)->factory;
  factory->first_free_thunk_ = thunk;

  factory->delegate_->OnFunctionExit(thunk, cycles);

  return thunk->caller;
}

}  // namespace client
}  // namespace agent
<|endoftext|>


<commit_before>#include "engine/polyline_compressor.hpp"

#include <boost/assert.hpp>
#include <cstddef>
#include <cstdlib>
#include <cmath>
#include <algorithm>

namespace osrm
{
namespace engine
{
namespace /*detail*/ // anonymous to keep TU local
{

std::string encode(int number_to_encode)
{
    std::string output;
    while (number_to_encode >= 0x20)
    {
        const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
        output += static_cast<char>(next_value);
        number_to_encode >>= 5;
    }

    number_to_encode += 63;
    output += static_cast<char>(number_to_encode);
    return output;
}

std::string encode(std::vector<int> &numbers)
{
    std::string output;
    for (auto &number : numbers)
    {
        bool isNegative = number < 0;

        if (isNegative)
        {
            const unsigned binary = std::llabs(number);
            const unsigned twos = (~binary) + 1u;
            number = twos;
        }

        number <<= 1u;

        if (isNegative)
        {
            number = ~number;
        }
    }
    for (const int number : numbers)
    {
        output += encode(number);
    }
    return output;
}
} // anonymous ns

std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end)
{
    auto size = std::distance(begin, end);
    if (size == 0)
    {
        return {};
    }

    std::vector<int> delta_numbers;
    BOOST_ASSERT(size > 0);
    delta_numbers.reserve((size - 1) * 2);
    util::Coordinate previous_coordinate{util::FixedLongitude(0), util::FixedLatitude(0)};
    std::for_each(begin, end, [&delta_numbers, &previous_coordinate](const util::Coordinate loc)
                  {
                      const int lat_diff = static_cast<int>(loc.lat - previous_coordinate.lat) *
                                           detail::COORDINATE_TO_POLYLINE;
                      const int lon_diff = static_cast<int>(loc.lon - previous_coordinate.lon) *
                                           detail::COORDINATE_TO_POLYLINE;
                      delta_numbers.emplace_back(lat_diff);
                      delta_numbers.emplace_back(lon_diff);
                      previous_coordinate = loc;
                  });
    return encode(delta_numbers);
}
std::vector<util::Coordinate> decodePolyline(const std::string &geometry_string)
{
    std::vector<util::Coordinate> new_coordinates;
    int index = 0, len = geometry_string.size();
    int lat = 0, lng = 0;

    while (index < len)
    {
        int b, shift = 0, result = 0;
        do
        {
            b = geometry_string.at(index++) - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
        lat += dlat;

        shift = 0;
        result = 0;
        do
        {
            b = geometry_string.at(index++) - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
        lng += dlng;

        util::Coordinate p;
        p.lat = util::FixedLatitude(lat * detail::POLYLINE_TO_COORDINATE);
        p.lon = util::FixedLongitude(lng * detail::POLYLINE_TO_COORDINATE);
        new_coordinates.push_back(p);
    }

    return new_coordinates;
}
}
}
<commit_msg>Fix numerical problems with polyline<commit_after>#include "engine/polyline_compressor.hpp"

#include <boost/assert.hpp>
#include <cstddef>
#include <cstdlib>
#include <cmath>
#include <algorithm>

namespace osrm
{
namespace engine
{
namespace /*detail*/ // anonymous to keep TU local
{

std::string encode(int number_to_encode)
{
    std::string output;
    while (number_to_encode >= 0x20)
    {
        const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
        output += static_cast<char>(next_value);
        number_to_encode >>= 5;
    }

    number_to_encode += 63;
    output += static_cast<char>(number_to_encode);
    return output;
}

std::string encode(std::vector<int> &numbers)
{
    std::string output;
    for (auto &number : numbers)
    {
        bool isNegative = number < 0;

        if (isNegative)
        {
            const unsigned binary = std::llabs(number);
            const unsigned twos = (~binary) + 1u;
            number = twos;
        }

        number <<= 1u;

        if (isNegative)
        {
            number = ~number;
        }
    }
    for (const int number : numbers)
    {
        output += encode(number);
    }
    return output;
}
} // anonymous ns

std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end)
{
    auto size = std::distance(begin, end);
    if (size == 0)
    {
        return {};
    }

    std::vector<int> delta_numbers;
    BOOST_ASSERT(size > 0);
    delta_numbers.reserve((size - 1) * 2);
    int current_lat = 0;
    int current_lon = 0;
    std::for_each(begin, end, [&delta_numbers, &current_lat, &current_lon](const util::Coordinate loc)
                  {
                      const int lat_diff = std::round(static_cast<int>(loc.lat) * detail::COORDINATE_TO_POLYLINE) - current_lat;
                      const int lon_diff = std::round(static_cast<int>(loc.lon) * detail::COORDINATE_TO_POLYLINE) - current_lon;
                      delta_numbers.emplace_back(lat_diff);
                      delta_numbers.emplace_back(lon_diff);
                      current_lat += lat_diff;
                      current_lon += lon_diff;
                  });
    return encode(delta_numbers);
}
std::vector<util::Coordinate> decodePolyline(const std::string &geometry_string)
{
    std::vector<util::Coordinate> new_coordinates;
    int index = 0, len = geometry_string.size();
    int lat = 0, lng = 0;

    while (index < len)
    {
        int b, shift = 0, result = 0;
        do
        {
            b = geometry_string.at(index++) - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
        lat += dlat;

        shift = 0;
        result = 0;
        do
        {
            b = geometry_string.at(index++) - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
        lng += dlng;

        util::Coordinate p;
        p.lat = util::FixedLatitude(lat * detail::POLYLINE_TO_COORDINATE);
        p.lon = util::FixedLongitude(lng * detail::POLYLINE_TO_COORDINATE);
        new_coordinates.push_back(p);
    }

    return new_coordinates;
}
}
}
<|endoftext|>


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

Daemon GPL Source Code
Copyright (C) 2012 Unvanquished Developers

This file is part of the Daemon GPL Source Code (Daemon Source Code).

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

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

You should have received a copy of the GNU General Public License
along with Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

extern "C"
{
#include "q_shared.h"
#include "qcommon.h"
#include "../../libs/findlocale/findlocale.h"
}

#include "../../libs/tinygettext/tinygettext.hpp"
#include <sstream>
#include <iostream>

using namespace tinygettext;
// Ugly char buffer
static char gettextbuffer[ MAX_STRING_CHARS ];

DictionaryManager trans_manager;
DictionaryManager trans_managergame;
Dictionary        trans_dict;
Dictionary        trans_dictgame;

cvar_t            *language;
cvar_t            *language_debug;
cvar_t            *trans_encodings;
cvar_t            *trans_languages;
bool              enabled = false;
int               modificationCount=0;

#define _(x) Trans_Gettext(x)
#define C_(x, y) Trans_Pgettext(x, y)

/*
====================
Trans_ReturnLanguage

Return a loaded language. If desired language is not found, return closest match.
If no languages are close, force English.
====================
*/
Language Trans_ReturnLanguage( const char *lang )
{
	int bestScore = 0;
	Language bestLang, language = Language::from_env( std::string( lang ) );

	std::set<Language> langs = trans_manager.get_languages();
	for( std::set<Language>::iterator i = langs.begin(); i != langs.end(); i++ )
	{
		int score = Language::match( language, *i );

		if( score > bestScore )
		{
			bestScore = score;
			bestLang = *i;
		}
	}

	// Return "en" if language not found
	if( !bestLang )
	{
		Com_Printf( _("^3WARNING:^7 Language \"%s\" (%s) not found. Default to \"English\" (en)\n"),
					language.get_name().empty() ? _("Unknown Language") : language.get_name().c_str(),
					lang );
		bestLang = Language::from_env( "en" );
	}

	return bestLang;
}

extern "C" void Trans_UpdateLanguage_f( void )
{
	if( !enabled ) { return; }
	Language lang = Trans_ReturnLanguage( language->string );
	trans_dict = trans_manager.get_dictionary( lang );
	trans_dictgame = trans_managergame.get_dictionary( lang );
	Com_Printf(_( "Switched language to %s\n"), lang.get_name().c_str() );

#ifndef DEDICATED
	// update the default console keys string
	extern cvar_t *cl_consoleKeys; // should really #include client.h
	Z_Free( cl_consoleKeys->resetString );
	cl_consoleKeys->resetString = CopyString( _("~ ` 0x7e 0x60") );
#endif
}

/*
============
Trans_Init
============
*/
extern "C" void Trans_Init( void )
{
	char                **poFiles, langList[ MAX_TOKEN_CHARS ] = "", encList[ MAX_TOKEN_CHARS ] = "";
	int                 numPoFiles, i;
	FL_Locale           *locale;
	std::set<Language>  langs;
	Language            lang;

	language = Cvar_Get( "language", "", CVAR_ARCHIVE );
	language_debug = Cvar_Get( "language_debug", "0", CVAR_ARCHIVE );
	trans_languages = Cvar_Get( "trans_languages", "", CVAR_ROM );
	trans_encodings = Cvar_Get( "trans_languages", "", CVAR_ROM );

	// Only detect locale if no previous language set.
	if( !language->string[0] )
	{
		FL_FindLocale( &locale, FL_MESSAGES );

		// Invalid or not found. Just use builtin language.
		if( !locale->lang || !locale->lang[0] || !locale->country || !locale->country[0] )
		{
			Cvar_Set( "language", "en" );
		}
		else
		{
			Cvar_Set( "language", va( "%s%s%s", locale->lang,
									  locale->country[0] ? "_" : "",
									  locale->country ) );
		}
	}

	poFiles = FS_ListFiles( "translation/client", ".po", &numPoFiles );

	// This assumes that the filenames in both folders are the same
	for( i = 0; i < numPoFiles; i++ )
	{
		int ret;
		char *buffer, language[ 6 ];

		if( FS_ReadFile( va( "translation/client/%s", poFiles[ i ] ), ( void ** ) &buffer ) > 0 )
		{
			COM_StripExtension2( poFiles[ i ], language, sizeof( language ) );
			std::stringstream ss( buffer );
			trans_manager.add_po( poFiles[ i ], ss, Language::from_env( std::string( language ) ) );
			FS_FreeFile( buffer );
		}
		else
		{
			Com_Printf(_( "^1ERROR: Could not open client translation: %s\n"), poFiles[ i ] );
		}

		if( FS_ReadFile( va( "translation/game/%s", poFiles[ i ] ), ( void ** ) &buffer ) > 0 )
		{
			COM_StripExtension2( poFiles[ i ], language, sizeof( language ) );
			std::stringstream ss( buffer );
			trans_managergame.add_po( poFiles[ i ], ss, Language::from_env( std::string( language ) ) );
			FS_FreeFile( buffer );
		}
		else
		{
			Com_Printf(_( "^1ERROR: Could not open game translation: %s\n"), poFiles[ i ] );
		}
	}
	FS_FreeFileList( poFiles );
	langs = trans_manager.get_languages();
	for( std::set<Language>::iterator p = langs.begin(); p != langs.end(); p++ )
	{
		Q_strcat( langList, sizeof( langList ), va( "\"%s\" ", p->get_name().c_str() ) );
		Q_strcat( encList, sizeof( encList ), va( "\"%s%s%s\" ", p->get_language().c_str(),
												  p->get_country().c_str()[0] ? "_" : "",
												  p->get_country().c_str() ) );
	}
	Cvar_Set( "trans_languages", langList );
	Cvar_Set( "trans_encodings", encList );
	Com_Printf(_( "Loaded %lu language(s)\n"), langs.size() );
	Cmd_AddCommand( "updatelanguage", Trans_UpdateLanguage_f );
	if( langs.size() )
	{
		lang = Trans_ReturnLanguage( language->string );
		trans_dict = trans_manager.get_dictionary( lang );
		trans_dictgame = trans_managergame.get_dictionary( lang );
		enabled = true;
	}
}

extern "C" const char* Trans_Gettext( const char *msgid )
{
	if( !enabled ) { return msgid; }
	Q_strncpyz( gettextbuffer, trans_dict.translate( msgid ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}

extern "C" const char* Trans_Pgettext( const char *ctxt, const char *msgid )
{
	if ( !enabled ) { return msgid; }
	Q_strncpyz( gettextbuffer, trans_dict.translate_ctxt( ctxt, msgid ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}

extern "C" const char* Trans_GettextGame( const char *msgid )
{
	if( !enabled ) { return msgid; }
	Q_strncpyz( gettextbuffer, trans_dictgame.translate( msgid ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}

extern "C" const char* Trans_PgettextGame( const char *ctxt, const char *msgid )
{
	if( !enabled ) { return msgid; }
	return trans_dictgame.translate_ctxt( std::string( ctxt ), std::string( msgid ) ).c_str();
}

extern "C" const char* Trans_GettextPlural( const char *msgid, const char *msgid_plural, int num )
{
	if( !enabled ) { return num == 1 ? msgid : msgid_plural; }
	Q_strncpyz( gettextbuffer, trans_dict.translate_plural( msgid, msgid_plural, num ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}

extern "C" const char* Trans_GettextGamePlural( const char *msgid, const char *msgid_plural, int num )
{
	if( !enabled ) { return num == 1 ? msgid : msgid_plural; }
	Q_strncpyz( gettextbuffer, trans_dictgame.translate_plural( msgid, msgid_plural, num ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}
<commit_msg>Fix some unused variable warnings<commit_after>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 2012 Unvanquished Developers

This file is part of the Daemon GPL Source Code (Daemon Source Code).

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

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

You should have received a copy of the GNU General Public License
along with Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

extern "C"
{
#include "q_shared.h"
#include "qcommon.h"
#include "../../libs/findlocale/findlocale.h"
}

#include "../../libs/tinygettext/tinygettext.hpp"
#include <sstream>
#include <iostream>

using namespace tinygettext;
// Ugly char buffer
static char gettextbuffer[ MAX_STRING_CHARS ];

DictionaryManager trans_manager;
DictionaryManager trans_managergame;
Dictionary        trans_dict;
Dictionary        trans_dictgame;

cvar_t            *language;
cvar_t            *language_debug;
cvar_t            *trans_encodings;
cvar_t            *trans_languages;
bool              enabled = false;
int               modificationCount=0;

#define _(x) Trans_Gettext(x)
#define C_(x, y) Trans_Pgettext(x, y)

/*
====================
Trans_ReturnLanguage

Return a loaded language. If desired language is not found, return closest match.
If no languages are close, force English.
====================
*/
Language Trans_ReturnLanguage( const char *lang )
{
	int bestScore = 0;
	Language bestLang, language = Language::from_env( std::string( lang ) );

	std::set<Language> langs = trans_manager.get_languages();
	for( std::set<Language>::iterator i = langs.begin(); i != langs.end(); i++ )
	{
		int score = Language::match( language, *i );

		if( score > bestScore )
		{
			bestScore = score;
			bestLang = *i;
		}
	}

	// Return "en" if language not found
	if( !bestLang )
	{
		Com_Printf( _("^3WARNING:^7 Language \"%s\" (%s) not found. Default to \"English\" (en)\n"),
					language.get_name().empty() ? _("Unknown Language") : language.get_name().c_str(),
					lang );
		bestLang = Language::from_env( "en" );
	}

	return bestLang;
}

extern "C" void Trans_UpdateLanguage_f( void )
{
	if( !enabled ) { return; }
	Language lang = Trans_ReturnLanguage( language->string );
	trans_dict = trans_manager.get_dictionary( lang );
	trans_dictgame = trans_managergame.get_dictionary( lang );
	Com_Printf(_( "Switched language to %s\n"), lang.get_name().c_str() );

#ifndef DEDICATED
	// update the default console keys string
	extern cvar_t *cl_consoleKeys; // should really #include client.h
	Z_Free( cl_consoleKeys->resetString );
	cl_consoleKeys->resetString = CopyString( _("~ ` 0x7e 0x60") );
#endif
}

/*
============
Trans_Init
============
*/
extern "C" void Trans_Init( void )
{
	char                **poFiles, langList[ MAX_TOKEN_CHARS ] = "", encList[ MAX_TOKEN_CHARS ] = "";
	int                 numPoFiles, i;
	FL_Locale           *locale;
	std::set<Language>  langs;
	Language            lang;

	language = Cvar_Get( "language", "", CVAR_ARCHIVE );
	language_debug = Cvar_Get( "language_debug", "0", CVAR_ARCHIVE );
	trans_languages = Cvar_Get( "trans_languages", "", CVAR_ROM );
	trans_encodings = Cvar_Get( "trans_languages", "", CVAR_ROM );

	// Only detect locale if no previous language set.
	if( !language->string[0] )
	{
		FL_FindLocale( &locale, FL_MESSAGES );

		// Invalid or not found. Just use builtin language.
		if( !locale->lang || !locale->lang[0] || !locale->country || !locale->country[0] )
		{
			Cvar_Set( "language", "en" );
		}
		else
		{
			Cvar_Set( "language", va( "%s%s%s", locale->lang,
									  locale->country[0] ? "_" : "",
									  locale->country ) );
		}
	}

	poFiles = FS_ListFiles( "translation/client", ".po", &numPoFiles );

	// This assumes that the filenames in both folders are the same
	for( i = 0; i < numPoFiles; i++ )
	{
		char *buffer, language[ 6 ];

		if( FS_ReadFile( va( "translation/client/%s", poFiles[ i ] ), ( void ** ) &buffer ) > 0 )
		{
			COM_StripExtension2( poFiles[ i ], language, sizeof( language ) );
			std::stringstream ss( buffer );
			trans_manager.add_po( poFiles[ i ], ss, Language::from_env( std::string( language ) ) );
			FS_FreeFile( buffer );
		}
		else
		{
			Com_Printf(_( "^1ERROR: Could not open client translation: %s\n"), poFiles[ i ] );
		}

		if( FS_ReadFile( va( "translation/game/%s", poFiles[ i ] ), ( void ** ) &buffer ) > 0 )
		{
			COM_StripExtension2( poFiles[ i ], language, sizeof( language ) );
			std::stringstream ss( buffer );
			trans_managergame.add_po( poFiles[ i ], ss, Language::from_env( std::string( language ) ) );
			FS_FreeFile( buffer );
		}
		else
		{
			Com_Printf(_( "^1ERROR: Could not open game translation: %s\n"), poFiles[ i ] );
		}
	}
	FS_FreeFileList( poFiles );
	langs = trans_manager.get_languages();
	for( std::set<Language>::iterator p = langs.begin(); p != langs.end(); p++ )
	{
		Q_strcat( langList, sizeof( langList ), va( "\"%s\" ", p->get_name().c_str() ) );
		Q_strcat( encList, sizeof( encList ), va( "\"%s%s%s\" ", p->get_language().c_str(),
												  p->get_country().c_str()[0] ? "_" : "",
												  p->get_country().c_str() ) );
	}
	Cvar_Set( "trans_languages", langList );
	Cvar_Set( "trans_encodings", encList );
	Com_Printf(_( "Loaded %lu language(s)\n"), langs.size() );
	Cmd_AddCommand( "updatelanguage", Trans_UpdateLanguage_f );
	if( langs.size() )
	{
		lang = Trans_ReturnLanguage( language->string );
		trans_dict = trans_manager.get_dictionary( lang );
		trans_dictgame = trans_managergame.get_dictionary( lang );
		enabled = true;
	}
}

extern "C" const char* Trans_Gettext( const char *msgid )
{
	if( !enabled ) { return msgid; }
	Q_strncpyz( gettextbuffer, trans_dict.translate( msgid ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}

extern "C" const char* Trans_Pgettext( const char *ctxt, const char *msgid )
{
	if ( !enabled ) { return msgid; }
	Q_strncpyz( gettextbuffer, trans_dict.translate_ctxt( ctxt, msgid ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}

extern "C" const char* Trans_GettextGame( const char *msgid )
{
	if( !enabled ) { return msgid; }
	Q_strncpyz( gettextbuffer, trans_dictgame.translate( msgid ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}

extern "C" const char* Trans_PgettextGame( const char *ctxt, const char *msgid )
{
	if( !enabled ) { return msgid; }
	return trans_dictgame.translate_ctxt( std::string( ctxt ), std::string( msgid ) ).c_str();
}

extern "C" const char* Trans_GettextPlural( const char *msgid, const char *msgid_plural, int num )
{
	if( !enabled ) { return num == 1 ? msgid : msgid_plural; }
	Q_strncpyz( gettextbuffer, trans_dict.translate_plural( msgid, msgid_plural, num ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}

extern "C" const char* Trans_GettextGamePlural( const char *msgid, const char *msgid_plural, int num )
{
	if( !enabled ) { return num == 1 ? msgid : msgid_plural; }
	Q_strncpyz( gettextbuffer, trans_dictgame.translate_plural( msgid, msgid_plural, num ).c_str(), sizeof( gettextbuffer ) );
	return gettextbuffer;
}
<|endoftext|>