<commit_before>#include <stdio.h>
#include <set>
#include <algorithm>

#ifdef USING_QT_UI
#include <QFileInfo>
#include <QDir>
#endif

#ifdef ANDROID
#include <zip.h>
#endif

#include "base/basictypes.h"
#include "base/logging.h"
#include "file/zip_read.h"

#ifdef ANDROID
uint8_t *ReadFromZip(zip *archive, const char* filename, size_t *size) {
	// Figure out the file size first.
	struct zip_stat zstat;
	zip_file *file = zip_fopen(archive, filename, 0);
	if (!file) {
		ELOG("Error opening %s from ZIP", filename);
		return 0;
	}
	zip_stat(archive, filename, ZIP_FL_NOCASE, &zstat);

	uint8_t *contents = new uint8_t[zstat.size + 1];
	zip_fread(file, contents, zstat.size);
	zip_fclose(file);
	contents[zstat.size] = 0;

	*size = zstat.size;
	return contents;
}

#endif

// The return is non-const because - why not?
uint8_t *ReadLocalFile(const char *filename, size_t *size) {
	FILE *file = fopen(filename, "rb");
	if (!file) {
		return 0;
	}
	fseek(file, 0, SEEK_END);
	size_t f_size = ftell(file);
	fseek(file, 0, SEEK_SET);
	uint8_t *contents = new uint8_t[f_size+1];
	fread(contents, 1, f_size, file);
	fclose(file);
	contents[f_size] = 0;
	*size = f_size;
	return contents;
}

#ifdef USING_QT_UI
uint8_t *AssetsAssetReader::ReadAsset(const char *path, size_t *size) {
	QFile asset(QString(":/assets/") + path);
	if (!asset.open(QIODevice::ReadOnly))
		return 0;

	uint8_t *contents = new uint8_t[asset.size()+1];
	memcpy(contents, (uint8_t*)asset.readAll().data(), asset.size());
	contents[asset.size()] = 0;
	*size = asset.size();
	asset.close();
	return contents;
}

bool AssetsAssetReader::GetFileListing(const char *path, std::vector<FileInfo> *listing, const char *filter = 0)
{
	QDir assetDir(QString(":/assets/") + path);
	QStringList filters = QString(filter).split(':', QString::SkipEmptyParts);
	for (int i = 0; i < filters.count(); i++)
		filters[i].prepend("*.");

	QFileInfoList infoList = assetDir.entryInfoList(filters, QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
	foreach(QFileInfo qinfo, infoList) {
		FileInfo info;
		info.name = qinfo.fileName().toStdString();
		info.fullName = qinfo.absoluteFilePath().remove(":/assets/").toStdString();
		info.exists = true;
		info.isWritable = false;
		info.isDirectory = qinfo.isDir();
		listing->push_back(info);
	}
	return true;
}

bool AssetsAssetReader::GetFileInfo(const char *path, FileInfo *info) {
	QFileInfo qinfo(QString(":/assets/") + path);
	if (qinfo.exists()) {
		info->exists = false;
		info->size = 0;
		return false;
	}

	info->fullName = path;
	info->exists = true;
	info->isWritable = false;
	info->isDirectory = qinfo.isDir();
	info->size = qinfo.size();
	return true;
}

#endif

#ifdef ANDROID

ZipAssetReader::ZipAssetReader(const char *zip_file, const char *in_zip_path) {
	zip_file_ = zip_open(zip_file, 0, NULL);
	strcpy(in_zip_path_, in_zip_path);
	if (!zip_file_) {
		ELOG("Failed to open %s as a zip file", zip_file);
	}

	std::vector<FileInfo> info;
	GetFileListing("assets", &info, 0);
	for (int i = 0; i < info.size(); i++) {
		if (info[i].isDirectory) {
			DLOG("Directory: %s", info[i].name.c_str());
		} else {
			DLOG("File: %s", info[i].name.c_str());
		}
	}
}

ZipAssetReader::~ZipAssetReader() {
	zip_close(zip_file_);
}

uint8_t *ZipAssetReader::ReadAsset(const char *path, size_t *size) {
	char temp_path[1024];
	strcpy(temp_path, in_zip_path_);
	strcat(temp_path, path);
	return ReadFromZip(zip_file_, temp_path, size);
}

bool ZipAssetReader::GetFileListing(const char *path, std::vector<FileInfo> *listing, const char *filter = 0)
{
	DLOG("Zip path: %s", path);
	std::set<std::string> filters;
	std::string tmp;
	if (filter) {
		while (*filter) {
			if (*filter == ':') {
				filters.insert(tmp);
				tmp = "";
			} else {
				tmp.push_back(*filter);
			}
			filter++;
		}
	}
	if (tmp.size())
		filters.insert(tmp);

	// We just loop through the whole ZIP file and deduce what files are in this directory, and what subdirectories there are.
	std::set<std::string> files;
	std::set<std::string> directories;
	int numFiles = zip_get_num_files(zip_file_);
	size_t pathlen = strlen(path);
	if (path[pathlen-1] == '/')
		pathlen--;
	for (int i = 0; i < numFiles; i++) {
		const char* name = zip_get_name(zip_file_, i, 0);
		if (!name)
			continue;
		if (!memcmp(name, path, pathlen)) {
			// The prefix is right. Let's see if this is a file or path.
			char *slashPos = strchr(name + pathlen + 1, '/');
			if (slashPos != 0) {
				// A directory.
				std::string dirName = std::string(name + pathlen + 1, slashPos - (name + pathlen + 1));
				directories.insert(dirName);
			} else {
				files.insert(std::string(name + pathlen + 1));
			}
		}
	}

	for (auto diter = directories.begin(); diter != directories.end(); ++diter) {
		FileInfo info;
		info.name = *diter;
		info.fullName = std::string(path);
		if (info.fullName[info.fullName.size() - 1] == '/')
			info.fullName = info.fullName.substr(0, info.fullName.size() - 1);
		info.fullName += "/" + *diter;
		info.exists = true;
		info.isWritable = false;
		info.isDirectory = true;
		listing->push_back(info);
	}

	for (auto fiter = files.begin(); fiter != files.end(); ++fiter) {
		FileInfo info;
		info.name = *fiter;
		info.fullName = std::string(path);
		if (info.fullName[info.fullName.size() - 1] == '/')
			info.fullName = info.fullName.substr(0, info.fullName.size() - 1);
		info.fullName += "/" + *fiter;
		info.exists = true;
		info.isWritable = false;
		info.isDirectory = false;
		std::string ext = getFileExtension(info.fullName);
		if (filter) {
			if (filters.find(ext) == filters.end())
				continue;
		}
		listing->push_back(info);
	}

	std::sort(listing->begin(), listing->end());
	return true;
}

bool ZipAssetReader::GetFileInfo(const char *path, FileInfo *info) {
	struct zip_stat zstat;
	char temp_path[1024];
	strcpy(temp_path, in_zip_path_);
	strcat(temp_path, path);
	if (0 != zip_stat(zip_file_, temp_path, ZIP_FL_NOCASE, &zstat)) {
		// ZIP files do not have real directories, so we'll end up here if we
		// try to stat one. For now that's fine.
		info->exists = false;
		info->size = 0;
		return false;
	}

	info->fullName = path;
	info->exists = true; // TODO
	info->isWritable = false;
	info->isDirectory = false;    // TODO
	info->size = zstat.size;
	return true;
}

#endif

uint8_t *DirectoryAssetReader::ReadAsset(const char *path, size_t *size) {
	char new_path[1024] = {0};
	// Check if it already contains the path
	if (strlen(path) > strlen(path_) && 0 == memcmp(path, path_, strlen(path_))) {
	}
	else {
		strcpy(new_path, path_);
	}
	strcat(new_path, path);
	return ReadLocalFile(new_path, size);
}

bool DirectoryAssetReader::GetFileListing(const char *path, std::vector<FileInfo> *listing, const char *filter = 0)
{
	char new_path[1024] = {0};
	// Check if it already contains the path
	if (strlen(path) > strlen(path_) && 0 == memcmp(path, path_, strlen(path_))) {
	}
	else {
		strcpy(new_path, path_);
	}
	strcat(new_path, path);
	FileInfo info;
	if (!getFileInfo(new_path, &info))
		return false;

	if (info.isDirectory)
	{
		getFilesInDir(new_path, listing, filter);
		return true;
	}
	else
	{
		return false;
	}
}

bool DirectoryAssetReader::GetFileInfo(const char *path, FileInfo *info)
{
	char new_path[1024] = {0};
	// Check if it already contains the path
	if (strlen(path) > strlen(path_) && 0 == memcmp(path, path_, strlen(path_))) {
	}
	else {
		strcpy(new_path, path_);
	}
	strcat(new_path, path);
	return getFileInfo(new_path, info);
}

struct VFSEntry {
	const char *prefix;
	AssetReader *reader;
};

static VFSEntry entries[16];
static int num_entries = 0;

void VFSRegister(const char *prefix, AssetReader *reader) {
	entries[num_entries].prefix = prefix;
	entries[num_entries].reader = reader;
	DLOG("Registered VFS for prefix %s: %s", prefix, reader->toString().c_str());
	num_entries++;
}

void VFSShutdown() {
	for (int i = 0; i < num_entries; i++) {
		delete entries[i].reader;
	}
	num_entries = 0;
}

uint8_t *VFSReadFile(const char *filename, size_t *size) {
	if (filename[0] == '/') {
		// Local path, not VFS.
		ILOG("Not a VFS path: %s . Reading local file.", filename);
		return ReadLocalFile(filename, size);
	}

	int fn_len = (int)strlen(filename);
	for (int i = 0; i < num_entries; i++) {
		int prefix_len = (int)strlen(entries[i].prefix);
		if (prefix_len >= fn_len) continue;
		if (0 == memcmp(filename, entries[i].prefix, prefix_len)) {
			// ILOG("Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len);
			uint8_t *data = entries[i].reader->ReadAsset(filename + prefix_len, size);
			if (data)
				return data;
			else
				continue;
			// Else try the other registered file systems.
		}
	}
	return 0;
}

bool VFSGetFileListing(const char *path, std::vector<FileInfo> *listing, const char *filter)
{
	if (path[0] == '/') {
		// Local path, not VFS.
		ILOG("Not a VFS path: %s . Reading local directory.", path);
		return getFilesInDir(path, listing, filter);
	}

	int fn_len = (int)strlen(path);
	for (int i = 0; i < num_entries; i++) {
		int prefix_len = (int)strlen(entries[i].prefix);
		if (prefix_len >= fn_len) continue;
		if (0 == memcmp(path, entries[i].prefix, prefix_len)) {
			if (entries[i].reader->GetFileListing(path + prefix_len, listing, filter))
			{
				return true;
			}
		}
	}
	ELOG("Missing filesystem for %s", path);
	return false;
}

bool VFSGetFileInfo(const char *path, FileInfo *info)
{
	if (path[0] == '/') {
		// Local path, not VFS.
		ILOG("Not a VFS path: %s . Getting local file info.", path);
		return getFileInfo(path, info);
	}

	int fn_len = (int)strlen(path);
	for (int i = 0; i < num_entries; i++) {
		int prefix_len = (int)strlen(entries[i].prefix);
		if (prefix_len >= fn_len) continue;
		if (0 == memcmp(path, entries[i].prefix, prefix_len)) {
			if (entries[i].reader->GetFileInfo(path + prefix_len, info))
				return true;
			else
				continue;
		}
	}
	ELOG("Missing filesystem for %s", path);
	return false;
}
<commit_msg>Fix a typo that was causing VFS to fail for Qt.<commit_after>#include <stdio.h>
#include <set>
#include <algorithm>

#ifdef USING_QT_UI
#include <QFileInfo>
#include <QDir>
#endif

#ifdef ANDROID
#include <zip.h>
#endif

#include "base/basictypes.h"
#include "base/logging.h"
#include "file/zip_read.h"

#ifdef ANDROID
uint8_t *ReadFromZip(zip *archive, const char* filename, size_t *size) {
	// Figure out the file size first.
	struct zip_stat zstat;
	zip_file *file = zip_fopen(archive, filename, 0);
	if (!file) {
		ELOG("Error opening %s from ZIP", filename);
		return 0;
	}
	zip_stat(archive, filename, ZIP_FL_NOCASE, &zstat);

	uint8_t *contents = new uint8_t[zstat.size + 1];
	zip_fread(file, contents, zstat.size);
	zip_fclose(file);
	contents[zstat.size] = 0;

	*size = zstat.size;
	return contents;
}

#endif

// The return is non-const because - why not?
uint8_t *ReadLocalFile(const char *filename, size_t *size) {
	FILE *file = fopen(filename, "rb");
	if (!file) {
		return 0;
	}
	fseek(file, 0, SEEK_END);
	size_t f_size = ftell(file);
	fseek(file, 0, SEEK_SET);
	uint8_t *contents = new uint8_t[f_size+1];
	fread(contents, 1, f_size, file);
	fclose(file);
	contents[f_size] = 0;
	*size = f_size;
	return contents;
}

#ifdef USING_QT_UI
uint8_t *AssetsAssetReader::ReadAsset(const char *path, size_t *size) {
	QFile asset(QString(":/assets/") + path);
	if (!asset.open(QIODevice::ReadOnly))
		return 0;

	uint8_t *contents = new uint8_t[asset.size()+1];
	memcpy(contents, (uint8_t*)asset.readAll().data(), asset.size());
	contents[asset.size()] = 0;
	*size = asset.size();
	asset.close();
	return contents;
}

bool AssetsAssetReader::GetFileListing(const char *path, std::vector<FileInfo> *listing, const char *filter = 0)
{
	QDir assetDir(QString(":/assets/") + path);
	QStringList filters = QString(filter).split(':', QString::SkipEmptyParts);
	for (int i = 0; i < filters.count(); i++)
		filters[i].prepend("*.");

	QFileInfoList infoList = assetDir.entryInfoList(filters, QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
	foreach(QFileInfo qinfo, infoList) {
		FileInfo info;
		info.name = qinfo.fileName().toStdString();
		info.fullName = qinfo.absoluteFilePath().remove(":/assets/").toStdString();
		info.exists = true;
		info.isWritable = false;
		info.isDirectory = qinfo.isDir();
		listing->push_back(info);
	}
	return true;
}

bool AssetsAssetReader::GetFileInfo(const char *path, FileInfo *info) {
	QFileInfo qinfo(QString(":/assets/") + path);
	if (!qinfo.exists()) {
		info->exists = false;
		info->size = 0;
		return false;
	}

	info->fullName = path;
	info->exists = true;
	info->isWritable = false;
	info->isDirectory = qinfo.isDir();
	info->size = qinfo.size();
	return true;
}

#endif

#ifdef ANDROID

ZipAssetReader::ZipAssetReader(const char *zip_file, const char *in_zip_path) {
	zip_file_ = zip_open(zip_file, 0, NULL);
	strcpy(in_zip_path_, in_zip_path);
	if (!zip_file_) {
		ELOG("Failed to open %s as a zip file", zip_file);
	}

	std::vector<FileInfo> info;
	GetFileListing("assets", &info, 0);
	for (int i = 0; i < info.size(); i++) {
		if (info[i].isDirectory) {
			DLOG("Directory: %s", info[i].name.c_str());
		} else {
			DLOG("File: %s", info[i].name.c_str());
		}
	}
}

ZipAssetReader::~ZipAssetReader() {
	zip_close(zip_file_);
}

uint8_t *ZipAssetReader::ReadAsset(const char *path, size_t *size) {
	char temp_path[1024];
	strcpy(temp_path, in_zip_path_);
	strcat(temp_path, path);
	return ReadFromZip(zip_file_, temp_path, size);
}

bool ZipAssetReader::GetFileListing(const char *path, std::vector<FileInfo> *listing, const char *filter = 0)
{
	DLOG("Zip path: %s", path);
	std::set<std::string> filters;
	std::string tmp;
	if (filter) {
		while (*filter) {
			if (*filter == ':') {
				filters.insert(tmp);
				tmp = "";
			} else {
				tmp.push_back(*filter);
			}
			filter++;
		}
	}
	if (tmp.size())
		filters.insert(tmp);

	// We just loop through the whole ZIP file and deduce what files are in this directory, and what subdirectories there are.
	std::set<std::string> files;
	std::set<std::string> directories;
	int numFiles = zip_get_num_files(zip_file_);
	size_t pathlen = strlen(path);
	if (path[pathlen-1] == '/')
		pathlen--;
	for (int i = 0; i < numFiles; i++) {
		const char* name = zip_get_name(zip_file_, i, 0);
		if (!name)
			continue;
		if (!memcmp(name, path, pathlen)) {
			// The prefix is right. Let's see if this is a file or path.
			char *slashPos = strchr(name + pathlen + 1, '/');
			if (slashPos != 0) {
				// A directory.
				std::string dirName = std::string(name + pathlen + 1, slashPos - (name + pathlen + 1));
				directories.insert(dirName);
			} else {
				files.insert(std::string(name + pathlen + 1));
			}
		}
	}

	for (auto diter = directories.begin(); diter != directories.end(); ++diter) {
		FileInfo info;
		info.name = *diter;
		info.fullName = std::string(path);
		if (info.fullName[info.fullName.size() - 1] == '/')
			info.fullName = info.fullName.substr(0, info.fullName.size() - 1);
		info.fullName += "/" + *diter;
		info.exists = true;
		info.isWritable = false;
		info.isDirectory = true;
		listing->push_back(info);
	}

	for (auto fiter = files.begin(); fiter != files.end(); ++fiter) {
		FileInfo info;
		info.name = *fiter;
		info.fullName = std::string(path);
		if (info.fullName[info.fullName.size() - 1] == '/')
			info.fullName = info.fullName.substr(0, info.fullName.size() - 1);
		info.fullName += "/" + *fiter;
		info.exists = true;
		info.isWritable = false;
		info.isDirectory = false;
		std::string ext = getFileExtension(info.fullName);
		if (filter) {
			if (filters.find(ext) == filters.end())
				continue;
		}
		listing->push_back(info);
	}

	std::sort(listing->begin(), listing->end());
	return true;
}

bool ZipAssetReader::GetFileInfo(const char *path, FileInfo *info) {
	struct zip_stat zstat;
	char temp_path[1024];
	strcpy(temp_path, in_zip_path_);
	strcat(temp_path, path);
	if (0 != zip_stat(zip_file_, temp_path, ZIP_FL_NOCASE, &zstat)) {
		// ZIP files do not have real directories, so we'll end up here if we
		// try to stat one. For now that's fine.
		info->exists = false;
		info->size = 0;
		return false;
	}

	info->fullName = path;
	info->exists = true; // TODO
	info->isWritable = false;
	info->isDirectory = false;    // TODO
	info->size = zstat.size;
	return true;
}

#endif

uint8_t *DirectoryAssetReader::ReadAsset(const char *path, size_t *size) {
	char new_path[1024] = {0};
	// Check if it already contains the path
	if (strlen(path) > strlen(path_) && 0 == memcmp(path, path_, strlen(path_))) {
	}
	else {
		strcpy(new_path, path_);
	}
	strcat(new_path, path);
	return ReadLocalFile(new_path, size);
}

bool DirectoryAssetReader::GetFileListing(const char *path, std::vector<FileInfo> *listing, const char *filter = 0)
{
	char new_path[1024] = {0};
	// Check if it already contains the path
	if (strlen(path) > strlen(path_) && 0 == memcmp(path, path_, strlen(path_))) {
	}
	else {
		strcpy(new_path, path_);
	}
	strcat(new_path, path);
	FileInfo info;
	if (!getFileInfo(new_path, &info))
		return false;

	if (info.isDirectory)
	{
		getFilesInDir(new_path, listing, filter);
		return true;
	}
	else
	{
		return false;
	}
}

bool DirectoryAssetReader::GetFileInfo(const char *path, FileInfo *info)
{
	char new_path[1024] = {0};
	// Check if it already contains the path
	if (strlen(path) > strlen(path_) && 0 == memcmp(path, path_, strlen(path_))) {
	}
	else {
		strcpy(new_path, path_);
	}
	strcat(new_path, path);
	return getFileInfo(new_path, info);
}

struct VFSEntry {
	const char *prefix;
	AssetReader *reader;
};

static VFSEntry entries[16];
static int num_entries = 0;

void VFSRegister(const char *prefix, AssetReader *reader) {
	entries[num_entries].prefix = prefix;
	entries[num_entries].reader = reader;
	DLOG("Registered VFS for prefix %s: %s", prefix, reader->toString().c_str());
	num_entries++;
}

void VFSShutdown() {
	for (int i = 0; i < num_entries; i++) {
		delete entries[i].reader;
	}
	num_entries = 0;
}

uint8_t *VFSReadFile(const char *filename, size_t *size) {
	if (filename[0] == '/') {
		// Local path, not VFS.
		ILOG("Not a VFS path: %s . Reading local file.", filename);
		return ReadLocalFile(filename, size);
	}

	int fn_len = (int)strlen(filename);
	for (int i = 0; i < num_entries; i++) {
		int prefix_len = (int)strlen(entries[i].prefix);
		if (prefix_len >= fn_len) continue;
		if (0 == memcmp(filename, entries[i].prefix, prefix_len)) {
			// ILOG("Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len);
			uint8_t *data = entries[i].reader->ReadAsset(filename + prefix_len, size);
			if (data)
				return data;
			else
				continue;
			// Else try the other registered file systems.
		}
	}
	return 0;
}

bool VFSGetFileListing(const char *path, std::vector<FileInfo> *listing, const char *filter)
{
	if (path[0] == '/') {
		// Local path, not VFS.
		ILOG("Not a VFS path: %s . Reading local directory.", path);
		return getFilesInDir(path, listing, filter);
	}

	int fn_len = (int)strlen(path);
	for (int i = 0; i < num_entries; i++) {
		int prefix_len = (int)strlen(entries[i].prefix);
		if (prefix_len >= fn_len) continue;
		if (0 == memcmp(path, entries[i].prefix, prefix_len)) {
			if (entries[i].reader->GetFileListing(path + prefix_len, listing, filter))
			{
				return true;
			}
		}
	}
	ELOG("Missing filesystem for %s", path);
	return false;
}

bool VFSGetFileInfo(const char *path, FileInfo *info)
{
	if (path[0] == '/') {
		// Local path, not VFS.
		ILOG("Not a VFS path: %s . Getting local file info.", path);
		return getFileInfo(path, info);
	}

	int fn_len = (int)strlen(path);
	for (int i = 0; i < num_entries; i++) {
		int prefix_len = (int)strlen(entries[i].prefix);
		if (prefix_len >= fn_len) continue;
		if (0 == memcmp(path, entries[i].prefix, prefix_len)) {
			if (entries[i].reader->GetFileInfo(path + prefix_len, info))
				return true;
			else
				continue;
		}
	}
	ELOG("Missing filesystem for %s", path);
	return false;
}
<|endoftext|>


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

#include "compare.h"
#include "op.h"

namespace ledger {

namespace {
  template <typename T>
  void push_sort_value(std::list<sort_value_t>& sort_values,
		       expr_t::ptr_op_t node, T * scope)
  {
    if (node->kind == expr_t::op_t::O_COMMA) {
      push_sort_value(sort_values, node->left(), scope);
      push_sort_value(sort_values, node->right(), scope);
    }
    else {
      bool inverted = false;

      if (node->kind == expr_t::op_t::O_NEG) {
	inverted = true;
	node = node->left();
      }

      sort_values.push_back(sort_value_t());
      sort_values.back().inverted = inverted;
      sort_values.back().value = expr_t(node).calc(*scope).reduced();
    }
  }
}

template <typename T>
void compare_items<T>::find_sort_values(std::list<sort_value_t>& sort_values,
					T * scope)
{
  push_sort_value(sort_values, sort_order.get_op(), scope);
}

template <>
bool compare_items<xact_t>::operator()(xact_t * left, xact_t * right)
{
  assert(left);
  assert(right);

  xact_t::xdata_t& lxdata(left->xdata());
  if (! lxdata.has_flags(XACT_EXT_SORT_CALC)) {
    find_sort_values(lxdata.sort_values, left);
    lxdata.add_flags(XACT_EXT_SORT_CALC);
  }

  xact_t::xdata_t& rxdata(right->xdata());
  if (! rxdata.has_flags(XACT_EXT_SORT_CALC)) {
    find_sort_values(rxdata.sort_values, right);
    rxdata.add_flags(XACT_EXT_SORT_CALC);
  }

  return sort_value_is_less_than(lxdata.sort_values, rxdata.sort_values);
}

template <>
bool compare_items<account_t>::operator()(account_t * left, account_t * right)
{
  assert(left);
  assert(right);

  account_t::xdata_t& lxdata(left->xdata());
  if (! lxdata.has_flags(ACCOUNT_EXT_SORT_CALC)) {
    find_sort_values(lxdata.sort_values, left);
    lxdata.add_flags(ACCOUNT_EXT_SORT_CALC);
  }

  account_t::xdata_t& rxdata(right->xdata());
  if (! rxdata.has_flags(ACCOUNT_EXT_SORT_CALC)) {
    find_sort_values(rxdata.sort_values, right);
    rxdata.add_flags(ACCOUNT_EXT_SORT_CALC);
  }

  return sort_value_is_less_than(lxdata.sort_values, rxdata.sort_values);
}

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

#include "compare.h"
#include "op.h"

namespace ledger {

namespace {
  template <typename T>
  void push_sort_value(std::list<sort_value_t>& sort_values,
		       expr_t::ptr_op_t node, T * scope)
  {
    if (node->kind == expr_t::op_t::O_COMMA) {
      push_sort_value(sort_values, node->left(), scope);
      push_sort_value(sort_values, node->right(), scope);
    }
    else {
      bool inverted = false;

      if (node->kind == expr_t::op_t::O_NEG) {
	inverted = true;
	node = node->left();
      }

      sort_values.push_back(sort_value_t());
      sort_values.back().inverted = inverted;
      sort_values.back().value = expr_t(node).calc(*scope).reduced();

      if (sort_values.back().value.is_null())
	throw calc_error("Could not determine sorting value based an expression");
    }
  }
}

template <typename T>
void compare_items<T>::find_sort_values(std::list<sort_value_t>& sort_values,
					T * scope)
{
  push_sort_value(sort_values, sort_order.get_op(), scope);
}

template <>
bool compare_items<xact_t>::operator()(xact_t * left, xact_t * right)
{
  assert(left);
  assert(right);

  xact_t::xdata_t& lxdata(left->xdata());
  if (! lxdata.has_flags(XACT_EXT_SORT_CALC)) {
    find_sort_values(lxdata.sort_values, left);
    lxdata.add_flags(XACT_EXT_SORT_CALC);
  }

  xact_t::xdata_t& rxdata(right->xdata());
  if (! rxdata.has_flags(XACT_EXT_SORT_CALC)) {
    find_sort_values(rxdata.sort_values, right);
    rxdata.add_flags(XACT_EXT_SORT_CALC);
  }

  return sort_value_is_less_than(lxdata.sort_values, rxdata.sort_values);
}

template <>
bool compare_items<account_t>::operator()(account_t * left, account_t * right)
{
  assert(left);
  assert(right);

  account_t::xdata_t& lxdata(left->xdata());
  if (! lxdata.has_flags(ACCOUNT_EXT_SORT_CALC)) {
    find_sort_values(lxdata.sort_values, left);
    lxdata.add_flags(ACCOUNT_EXT_SORT_CALC);
  }

  account_t::xdata_t& rxdata(right->xdata());
  if (! rxdata.has_flags(ACCOUNT_EXT_SORT_CALC)) {
    find_sort_values(rxdata.sort_values, right);
    rxdata.add_flags(ACCOUNT_EXT_SORT_CALC);
  }

  return sort_value_is_less_than(lxdata.sort_values, rxdata.sort_values);
}

} // namespace ledger
<|endoftext|>


<commit_before>#include <fstream>
#include <string>
#include <type_traits>
#include <variant>
#include <boost/hana/functional/overload.hpp>
#include <tmxpp.hpp>
#include <tmxpp/exceptions.hpp>
#include <tmxpp/impl/Xml.hpp>
#include <tmxpp/impl/tmx_info.hpp>
#include <tmxpp/impl/to_string_flipped_global_ids.hpp>
#include <tmxpp/impl/write_poly.hpp>
#include <tmxpp/impl/write_utility.hpp>

namespace tmxpp {

namespace impl {

using namespace tmx_info;

template <class Number>
void write(Size<Number> sz, Xml::Element elem)
{
    add(elem, size_width, sz.w);
    add(elem, size_height, sz.h);
}

void write_tile(pxSize sz, Xml::Element elem)
{
    add(elem, tile_size_width, sz.w);
    add(elem, tile_size_height, sz.h);
}

// Properties ------------------------------------------------------------------

void write(const Property::Value& value, Xml::Element prop)
{
    auto add = [=](Xml::Attribute::Value alternative, auto value) {
        prop.add(property_alternative, alternative);
        impl::add(prop, property_value, value);
    };

    std::visit(
        boost::hana::overload(
            [=](int i) { add(property_alternative_int, i); },
            [=](double d) { add(property_alternative_double, d); },
            [=](bool b) {
                add(property_alternative_bool,
                    get(b ? property_value_true : property_value_false));
            },
            [=](Color c) { add(property_alternative_color, c); },
            [=](File f) { add(property_alternative_file, f.string()); },
            [=](const std::string& s) {
                prop.add(property_alternative, property_alternative_string);

                if (bool is_multiline{s.find('\n') != std::string::npos})
                    prop.value(Xml::Element::Value{s});
                else
                    impl::add(prop, property_value, s);
            }),
        value);
}

void write(const Property& p, Xml::Element elem)
{
    add(elem, property_name, p.name);
    write(p.value, elem);
}

void write(const Properties& ps, Xml::Element parent)
{
    if (ps.empty())
        return;

    auto elem{parent.add(properties)};

    for (const auto& p : ps)
        write(p, elem.add(property));
}

// Image -----------------------------------------------------------------------

void write(const Image& img, Xml::Element elem)
{
    add(elem, image_source, img.source.string());
    add(elem, image_transparent, img.transparent);
    write(img.size, elem);
}

// Animation -------------------------------------------------------------------

void write(Frame f, Xml::Element elem)
{
    add(elem, frame_local_id, f.local_id);
    add(elem, frame_duration, f.duration.count());
}

void write(const Animation& anim, Xml::Element parent)
{
    if (anim.empty())
        return;

    auto elem{parent.add(animation)};

    for (const auto& f : anim)
        write(f, elem.add(frame));
}

// Map::Tile_set ---------------------------------------------------------------

void write_tile(Offset o, Xml::Element parent)
{
    if (o == Offset{})
        return;

    auto elem{parent.add(tile_offset)};

    add(elem, tile_offset_x, o.x);
    add(elem, tile_offset_y, o.y);
}

void write(const Object_layer& l, Xml::Element elem);

template <class Tile>
std::enable_if_t<
    std::is_same_v<Tile, Tile_set::Tile> ||
    std::is_same_v<Tile, Image_collection::Tile>>
write(const Tile& tile, Xml::Element elem)
{
    add(elem, tile_set_tile_local_id, tile.local_id);
    write(tile.properties, elem);
    // clang-format off
    if constexpr (std::is_same_v<Tile, Image_collection::Tile>)
        write(tile.image, elem.add(image));
    // clang-format on
    if (const auto& cs{tile.collision_shape})
        write(*cs, elem.add(object_layer));
    write(tile.animation, elem);
}

template <class Tiles>
std::enable_if_t<
    std::is_same_v<Tiles, Tile_set::Tiles> ||
    std::is_same_v<Tiles, Image_collection::Tiles>>
write(const Tiles& ts, Xml::Element parent)
{
    if (ts.empty())
        return;

    for (const auto& t : ts)
        write(t, parent.add(tile_set_tile));
}

template <class Tset>
void map_tile_set_visitor(const Tset& ts, Xml::Element elem)
{
    add(elem, tile_set_first_global_id, ts.first_global_id);
    non_empty_add(elem, tile_set_tsx, ts.tsx);
    add(elem, tile_set_name, ts.name);
    // clang-format off
    if constexpr (std::is_same_v<Tset, Tile_set>) {
        write_tile(ts.tile_size, elem);
        non_default_add(elem, tile_set_spacing, ts.spacing);
        non_default_add(elem, tile_set_margin, ts.margin);
        add(elem, tile_set_tile_count, ts.size.w * ts.size.h);
        add(elem, tile_set_columns, ts.size.w);
    }
    else {
        write_tile(ts.max_tile_size, elem);
        add(elem, tile_set_tile_count, ts.tile_count);
        add(elem, tile_set_columns, ts.columns);
    };
    write_tile(ts.tile_offset, elem);
    write(ts.properties, elem);
    if constexpr (std::is_same_v<Tset, Tile_set>)
            write(ts.image, elem.add(image));
    // clang-format on
    write(ts.tiles, elem);
}

void write(const Map::Tile_set& ts, Xml::Element elem)
{
    std::visit([elem](const auto& ts) { map_tile_set_visitor(ts, elem); }, ts);
}

// Data ------------------------------------------------------------------------

void write(Data::Encoding e, Xml::Element data)
{
    data.add(data_encoding, [e] {
        switch (e) {
        case Data::Encoding::csv: return data_encoding_csv;
        case Data::Encoding::base64: return data_encoding_base64;
        default: throw Exception{""};
        }
    }());
}

void write(Data::Compression c, Xml::Element data)
{
    if (c == Data::Compression::none)
        return;

    data.add(data_compression, [c] {
        switch (c) {
        case Data::Compression::zlib: return data_compression_zlib;
        default: throw Exception{""};
        }
    }());
}

void write(const Data& d, Xml::Element elem, iSize size)
{
    if (d.encoding != Data::Encoding::csv ||
        d.compression != Data::Compression::none)
        throw Exception{"Can only handle csv-encoded data."};

    write(d.encoding, elem);
    write(d.compression, elem);
    elem.value(to_string(d.flipped_global_ids, size));
}

// Object ----------------------------------------------------------------------

void write(Point p, Xml::Element obj)
{
    add(obj, point_x, p.x);
    add(obj, point_y, p.y);
}

void write_object(pxSize sz, Xml::Element obj)
{
    non_default_add(obj, size_width, sz.w);
    non_default_add(obj, size_height, sz.h);
}

void write(const Object::Shape& s, Xml::Element obj)
{
    std::visit(
        boost::hana::overload(
            [obj](Object::Rectangle r) { write_object(r.size, obj); },
            [obj](Object::Ellipse e) {
                write_object(e.size, obj);
                obj.add(object_ellipse);
            },
            [obj](const auto& poly) { write(poly, obj); }),
        s);
}

void write(const Object& obj, Xml::Element elem)
{
    add(elem, object_unique_id, obj.unique_id);
    non_empty_add(elem, object_name, obj.name);
    non_empty_add(elem, object_type, obj.type);
    non_default_add(elem, object_global_id, obj.global_id);
    write(obj.position, elem);
    write(obj.shape, elem);
    non_default_add(elem, object_clockwise_rotation, obj.clockwise_rotation);
    if (!obj.visible)
        add(elem, object_visible, "0");
    write(obj.properties, elem);
}

// Map::Layer ------------------------------------------------------------------

void write(Object_layer::Draw_order do_, Xml::Element layer)
{
    layer.add(object_layer_draw_order, [do_] {
        switch (do_) {
        case Object_layer::Draw_order::top_down:
            return object_layer_draw_order_top_down;
        case Object_layer::Draw_order::index:
            return object_layer_draw_order_index;
        default: throw Exception{""};
        }
    }());
}

void write(Offset o, Xml::Element layer)
{
    if (o == Offset{})
        return;

    add(layer, offset_x, o.x);
    add(layer, offset_y, o.y);
}

void write(const Object_layer::Objects& objs, Xml::Element elem)
{
    for (const auto& obj : objs)
        write(obj, elem.add(object));
}

template <class Layer>
void layer_visitor(const Layer& l, Xml::Element elem)
{
    // clang-format off
    if constexpr (std::is_same_v<Layer, Object_layer>) {
        add(elem, object_layer_color, l.color);
        write(l.draw_order, elem);
    }
    add(elem, layer_name, l.name);
    if constexpr (std::is_same_v<Layer, Tile_layer>)
        write(l.size, elem);
    non_default_add(elem, layer_opacity, l.opacity, Default{Unit_interval{1}});
    if (!l.visible)
        add(elem, layer_visible, "0");
    write(l.offset, elem);
    if constexpr (std::is_same_v<Layer, Image_layer>)
        if (auto img{l.image})
            write(*img, elem.add(image));
    write(l.properties, elem);
    if constexpr (std::is_same_v<Layer, Tile_layer>)
        write(l.data, elem.add(data), l.size);
    if constexpr (std::is_same_v<Layer, Object_layer>)
        write(l.objects, elem);
    // clang-format on
}

void write(const Object_layer& l, Xml::Element elem)
{
    layer_visitor(l, elem);
}

void write(const Map::Layer& l, Xml::Element map)
{
    std::visit(
        [map](const auto& l) {
            auto elem{map.add([] {
                using Layer = std::decay_t<decltype(l)>;
                // clang-format off
                if constexpr (std::is_same_v<Layer, Tile_layer>)
                    return tile_layer;
                if constexpr (std::is_same_v<Layer, Object_layer>)
                    return object_layer;
                if constexpr (std::is_same_v<Layer, Image_layer>)
                    return image_layer;
                // clang-format on
            }())};

            layer_visitor(l, elem);
        },
        l);
}

// Map -------------------------------------------------------------------------

void write(Map::Render_order ro, Xml::Element map)
{
    map.add(map_render_order, [ro] {
        switch (ro) {
        case Map::Render_order::right_down: return map_render_order_right_down;
        case Map::Render_order::right_up: return map_render_order_right_up;
        case Map::Render_order::left_down: return map_render_order_left_down;
        case Map::Render_order::left_up: return map_render_order_left_up;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered::Axis a, Xml::Element map)
{
    map.add(map_staggered_axis, [a] {
        switch (a) {
        case Map::Staggered::Axis::x: return map_staggered_axis_x;
        case Map::Staggered::Axis::y: return map_staggered_axis_y;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered::Index i, Xml::Element map)
{
    map.add(map_staggered_index, [i] {
        switch (i) {
        case Map::Staggered::Index::even: return map_staggered_index_even;
        case Map::Staggered::Index::odd: return map_staggered_index_odd;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered s, Xml::Element map)
{
    write(s.axis, map);
    write(s.index, map);
}

void write(Map::Hexagonal h, Xml::Element map)
{
    add(map, map_hexagonal_side_legth, h.side_length);
    write(static_cast<Map::Staggered>(h), map);
}

void write(
    Map::Orientation orient, Map::Render_order render_order, Xml::Element map)
{
    auto add = [=](Xml::Attribute::Value orient) {
        map.add(map_orientation, orient);

        write(render_order, map);
    };

    std::visit(
        boost::hana::overload(
            [=](Map::Orthogonal) { add(map_orthogonal); },
            [=](Map::Isometric) { add(map_isometric); },
            [=](Map::Staggered s) {
                add(map_staggered);
                write(s, map);
            },
            [=](Map::Hexagonal h) {
                add(map_hexagonal);
                write(h, map);
            }),
        orient);
}

void write(const Map::Tile_sets& tses, Xml::Element map)
{
    for (const auto& ts : tses)
        write(ts, map.add(tile_set));
}

void write(const Map::Layers& ls, Xml::Element map)
{
    for (const auto& l : ls)
        write(l, map);
}

void write(const Map& map, Xml::Element elem)
{
    add(elem, map_version, map.version);
    write(map.orientation, map.render_order, elem);
    write(map.size, elem);
    write_tile(map.general_tile_size, elem);
    add(elem, map_background, map.background);
    add(elem, map_next_unique_id, map.next_unique_id);
    write(map.properties, elem);
    write(map.tile_sets, elem);
    write(map.layers, elem);
}

} // namespace impl

void write(const Map& map, gsl::not_null<gsl::czstring<>> path)
{
    impl::Xml tmx{impl::tmx_info::map};

    impl::write(map, tmx.root());

    std::ofstream{path} << tmx;
}

void write(const Map::Tile_set&);
void write(const Tile_set&);
void write(const Image_collection&);

} // namespace tmxpp
<commit_msg>Make changes to match TMX output by Tiled<commit_after>#include <fstream>
#include <string>
#include <type_traits>
#include <variant>
#include <boost/hana/functional/overload.hpp>
#include <tmxpp.hpp>
#include <tmxpp/exceptions.hpp>
#include <tmxpp/impl/Xml.hpp>
#include <tmxpp/impl/tmx_info.hpp>
#include <tmxpp/impl/to_string_flipped_global_ids.hpp>
#include <tmxpp/impl/write_poly.hpp>
#include <tmxpp/impl/write_utility.hpp>

namespace tmxpp {

namespace impl {

using namespace tmx_info;

template <class Number>
void write(Size<Number> sz, Xml::Element elem)
{
    add(elem, size_width, sz.w);
    add(elem, size_height, sz.h);
}

void write_tile(pxSize sz, Xml::Element elem)
{
    add(elem, tile_size_width, sz.w);
    add(elem, tile_size_height, sz.h);
}

// Properties ------------------------------------------------------------------

void write(const Property::Value& value, Xml::Element prop)
{
    auto add = [=](Xml::Attribute::Value alternative, auto value) {
        prop.add(property_alternative, alternative);
        impl::add(prop, property_value, value);
    };

    std::visit(
        boost::hana::overload(
            [=](int i) { add(property_alternative_int, i); },
            [=](double d) {
                add(property_alternative_double, to_string<double>(d));
            },
            [=](bool b) {
                add(property_alternative_bool,
                    get(b ? property_value_true : property_value_false));
            },
            [=](Color c) { add(property_alternative_color, c); },
            [=](File f) { add(property_alternative_file, f.string()); },
            [=](const std::string& s) {
                if (bool is_multiline{s.find('\n') != std::string::npos})
                    prop.value(Xml::Element::Value{s});
                else
                    impl::add(prop, property_value, s);
            }),
        value);
}

void write(const Property& p, Xml::Element elem)
{
    add(elem, property_name, p.name);
    write(p.value, elem);
}

void write(const Properties& ps, Xml::Element parent)
{
    if (ps.empty())
        return;

    auto elem{parent.add(properties)};

    for (const auto& p : ps)
        write(p, elem.add(property));
}

// Image -----------------------------------------------------------------------

void write(const Image& img, Xml::Element elem)
{
    add(elem, image_source, img.source.string());
    add(elem, image_transparent, img.transparent);
    write(img.size, elem);
}

// Animation -------------------------------------------------------------------

void write(Frame f, Xml::Element elem)
{
    add(elem, frame_local_id, f.local_id);
    add(elem, frame_duration, f.duration.count());
}

void write(const Animation& anim, Xml::Element parent)
{
    if (anim.empty())
        return;

    auto elem{parent.add(animation)};

    for (const auto& f : anim)
        write(f, elem.add(frame));
}

// Map::Tile_set ---------------------------------------------------------------

void write_tile(Offset o, Xml::Element parent)
{
    if (o == Offset{})
        return;

    auto elem{parent.add(tile_offset)};

    add(elem, tile_offset_x, o.x);
    add(elem, tile_offset_y, o.y);
}

void write(const Object_layer& l, Xml::Element elem);

template <class Tile>
std::enable_if_t<
    std::is_same_v<Tile, Tile_set::Tile> ||
    std::is_same_v<Tile, Image_collection::Tile>>
write(const Tile& tile, Xml::Element elem)
{
    add(elem, tile_set_tile_local_id, tile.local_id);
    write(tile.properties, elem);
    // clang-format off
    if constexpr (std::is_same_v<Tile, Image_collection::Tile>)
        write(tile.image, elem.add(image));
    // clang-format on
    if (const auto& cs{tile.collision_shape})
        write(*cs, elem.add(object_layer));
    write(tile.animation, elem);
}

template <class Tiles>
std::enable_if_t<
    std::is_same_v<Tiles, Tile_set::Tiles> ||
    std::is_same_v<Tiles, Image_collection::Tiles>>
write(const Tiles& ts, Xml::Element parent)
{
    if (ts.empty())
        return;

    for (const auto& t : ts)
        write(t, parent.add(tile_set_tile));
}

template <class Tset>
void map_tile_set_visitor(const Tset& ts, Xml::Element elem)
{
    add(elem, tile_set_first_global_id, ts.first_global_id);
    non_empty_add(elem, tile_set_tsx, ts.tsx);
    add(elem, tile_set_name, ts.name);
    // clang-format off
    if constexpr (std::is_same_v<Tset, Tile_set>) {
        write_tile(ts.tile_size, elem);
        non_default_add(elem, tile_set_spacing, ts.spacing);
        non_default_add(elem, tile_set_margin, ts.margin);
        add(elem, tile_set_tile_count, ts.size.w * ts.size.h);
        add(elem, tile_set_columns, ts.size.w);
    }
    else {
        write_tile(ts.max_tile_size, elem);
        add(elem, tile_set_tile_count, ts.tile_count);
        add(elem, tile_set_columns, ts.columns);
    };
    write_tile(ts.tile_offset, elem);
    write(ts.properties, elem);
    if constexpr (std::is_same_v<Tset, Tile_set>)
            write(ts.image, elem.add(image));
    // clang-format on
    write(ts.tiles, elem);
}

void write(const Map::Tile_set& ts, Xml::Element elem)
{
    std::visit([elem](const auto& ts) { map_tile_set_visitor(ts, elem); }, ts);
}

// Data ------------------------------------------------------------------------

void write(Data::Encoding e, Xml::Element data)
{
    data.add(data_encoding, [e] {
        switch (e) {
        case Data::Encoding::csv: return data_encoding_csv;
        case Data::Encoding::base64: return data_encoding_base64;
        default: throw Exception{""};
        }
    }());
}

void write(Data::Compression c, Xml::Element data)
{
    if (c == Data::Compression::none)
        return;

    data.add(data_compression, [c] {
        switch (c) {
        case Data::Compression::zlib: return data_compression_zlib;
        default: throw Exception{""};
        }
    }());
}

void write(const Data& d, Xml::Element elem, iSize size)
{
    if (d.encoding != Data::Encoding::csv ||
        d.compression != Data::Compression::none)
        throw Exception{"Can only handle csv-encoded data."};

    write(d.encoding, elem);
    write(d.compression, elem);
    elem.value(to_string(d.flipped_global_ids, size));
}

// Object ----------------------------------------------------------------------

void write(Point p, Xml::Element obj)
{
    add(obj, point_x, p.x);
    add(obj, point_y, p.y);
}

void write_object(pxSize sz, Xml::Element obj)
{
    non_default_add(obj, size_width, sz.w);
    non_default_add(obj, size_height, sz.h);
}

void write(const Object::Shape& s, Xml::Element obj)
{
    std::visit(
        boost::hana::overload(
            [obj](Object::Rectangle r) { write_object(r.size, obj); },
            [obj](Object::Ellipse e) {
                write_object(e.size, obj);
                obj.add(object_ellipse);
            },
            [obj](const auto& poly) { write(poly, obj); }),
        s);
}

void write(const Object& obj, Xml::Element elem)
{
    add(elem, object_unique_id, obj.unique_id);
    non_empty_add(elem, object_name, obj.name);
    non_empty_add(elem, object_type, obj.type);
    non_default_add(elem, object_global_id, obj.global_id);
    write(obj.position, elem);
    write(obj.shape, elem);
    non_default_add(elem, object_clockwise_rotation, obj.clockwise_rotation);
    if (!obj.visible)
        add(elem, object_visible, "0");
    write(obj.properties, elem);
}

// Map::Layer ------------------------------------------------------------------

void write(Object_layer::Draw_order do_, Xml::Element layer)
{
    if (do_ == Object_layer::Draw_order::top_down)
        return;

    layer.add(object_layer_draw_order, [do_] {
        switch (do_) {
        case Object_layer::Draw_order::index:
            return object_layer_draw_order_index;
        default: throw Exception{""};
        }
    }());
}

void write(Offset o, Xml::Element layer)
{
    if (o == Offset{})
        return;

    add(layer, offset_x, o.x);
    add(layer, offset_y, o.y);
}

void write(const Object_layer::Objects& objs, Xml::Element elem)
{
    for (const auto& obj : objs)
        write(obj, elem.add(object));
}

template <class Layer>
void layer_visitor(const Layer& l, Xml::Element elem)
{
    // clang-format off
    if constexpr (std::is_same_v<Layer, Object_layer>) {
        add(elem, object_layer_color, l.color);
        write(l.draw_order, elem);
    }
    non_empty_add(elem, layer_name, l.name);
    if constexpr (std::is_same_v<Layer, Tile_layer>)
        write(l.size, elem);
    if (!l.visible)
        add(elem, layer_visible, "0");
    non_default_add(elem, layer_opacity, l.opacity, Default{Unit_interval{1}});
    write(l.offset, elem);
    if constexpr (std::is_same_v<Layer, Image_layer>)
        if (auto img{l.image})
            write(*img, elem.add(image));
    write(l.properties, elem);
    if constexpr (std::is_same_v<Layer, Tile_layer>)
        write(l.data, elem.add(data), l.size);
    if constexpr (std::is_same_v<Layer, Object_layer>)
        write(l.objects, elem);
    // clang-format on
}

void write(const Object_layer& l, Xml::Element elem)
{
    layer_visitor(l, elem);
}

void write(const Map::Layer& l, Xml::Element map)
{
    std::visit(
        [map](const auto& l) {
            auto elem{map.add([] {
                using Layer = std::decay_t<decltype(l)>;
                // clang-format off
                if constexpr (std::is_same_v<Layer, Tile_layer>)
                    return tile_layer;
                if constexpr (std::is_same_v<Layer, Object_layer>)
                    return object_layer;
                if constexpr (std::is_same_v<Layer, Image_layer>)
                    return image_layer;
                // clang-format on
            }())};

            layer_visitor(l, elem);
        },
        l);
}

// Map -------------------------------------------------------------------------

void write(Map::Render_order ro, Xml::Element map)
{
    map.add(map_render_order, [ro] {
        switch (ro) {
        case Map::Render_order::right_down: return map_render_order_right_down;
        case Map::Render_order::right_up: return map_render_order_right_up;
        case Map::Render_order::left_down: return map_render_order_left_down;
        case Map::Render_order::left_up: return map_render_order_left_up;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered::Axis a, Xml::Element map)
{
    map.add(map_staggered_axis, [a] {
        switch (a) {
        case Map::Staggered::Axis::x: return map_staggered_axis_x;
        case Map::Staggered::Axis::y: return map_staggered_axis_y;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered::Index i, Xml::Element map)
{
    map.add(map_staggered_index, [i] {
        switch (i) {
        case Map::Staggered::Index::even: return map_staggered_index_even;
        case Map::Staggered::Index::odd: return map_staggered_index_odd;
        default: throw Exception{""};
        }
    }());
}

void write(Map::Staggered s, Xml::Element map)
{
    write(s.axis, map);
    write(s.index, map);
}

void write(Map::Hexagonal h, Xml::Element map)
{
    add(map, map_hexagonal_side_legth, h.side_length);
    write(static_cast<Map::Staggered>(h), map);
}

void write(
    Map::Orientation orient, Map::Render_order render_order, Xml::Element map)
{
    auto add = [=](Xml::Attribute::Value orient) {
        map.add(map_orientation, orient);

        write(render_order, map);
    };

    std::visit(
        boost::hana::overload(
            [=](Map::Orthogonal) { add(map_orthogonal); },
            [=](Map::Isometric) { add(map_isometric); },
            [=](Map::Staggered s) {
                add(map_staggered);
                write(s, map);
            },
            [=](Map::Hexagonal h) {
                add(map_hexagonal);
                write(h, map);
            }),
        orient);
}

void write(const Map::Tile_sets& tses, Xml::Element map)
{
    for (const auto& ts : tses)
        write(ts, map.add(tile_set));
}

void write(const Map::Layers& ls, Xml::Element map)
{
    for (const auto& l : ls)
        write(l, map);
}

void write(const Map& map, Xml::Element elem)
{
    add(elem, map_version, map.version);
    write(map.orientation, map.render_order, elem);
    write(map.size, elem);
    write_tile(map.general_tile_size, elem);
    add(elem, map_background, map.background);
    add(elem, map_next_unique_id, map.next_unique_id);
    write(map.properties, elem);
    write(map.tile_sets, elem);
    write(map.layers, elem);
}

} // namespace impl

void write(const Map& map, gsl::not_null<gsl::czstring<>> path)
{
    impl::Xml tmx{impl::tmx_info::map};

    impl::write(map, tmx.root());

    std::ofstream{path} << tmx;
}

void write(const Map::Tile_set&);
void write(const Tile_set&);
void write(const Image_collection&);

} // namespace tmxpp
<|endoftext|>


<commit_before>#include "3RVX.h"
#include "Controllers\Volume\IVolume.h"
#include "Controllers\Volume\CoreAudio.h"
#include "LayeredWnd\LayeredWnd.h"
#include <Wtsapi32.h>

int APIENTRY
wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow) {
    using namespace Gdiplus;

    hInst = hInstance;

    GdiplusStartupInput gdiplusStartupInput;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    mainWnd = CreateMainWnd(hInstance);
    if (mainWnd == NULL)
        return EXIT_FAILURE;

    AllocConsole();
    FILE *in, *out, *err;
    freopen_s(&in, "CONIN$", "r", stdin);
    freopen_s(&out, "CONOUT$", "w", stdout);
    freopen_s(&err, "CONOUT$", "w", stderr);

    printf("Starting...\n");

    HRESULT hr = CoInitializeEx(NULL,
        COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    /* Tell the program to initialize */
    PostMessage(mainWnd, WM_3RVX_CONTROL, MSG_LOAD, NULL);

    /* Start the event loop */
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    GdiplusShutdown(gdiplusToken);

    return (int)msg.wParam;
}

void Init() {
    ca = new CoreAudio(mainWnd);
    ca->Init();

    /* Show a layered window */
    LayeredWnd *lw = new LayeredWnd(hInst, L"testing", L"test test");
    lw->Init();
    std::wstring filename(L"m.gif");
    Gdiplus::Bitmap *buff = Gdiplus::Bitmap::FromFile(filename.c_str(), false);
    printf("Last status: %d\n", buff->GetLastStatus());
    lw->Image(buff);
    lw->Show();

    WTSRegisterSessionNotification(mainWnd, NOTIFY_FOR_THIS_SESSION);

    HotkeyManager *hkManager = HotkeyManager::Instance();
    hkManager->Register(mainWnd, HKM_MOD_WIN + VK_BACK);
    hkManager->Register(mainWnd, HKM_MOD_WIN + HKM_MOUSE_WHUP);
}

HWND CreateMainWnd(HINSTANCE hInstance) {
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = NULL;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = NULL;
    wcex.cbWndExtra = NULL;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"3RVX";
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    if (!RegisterClassEx(&wcex)) {
        return NULL;
    }

    HWND hWnd = CreateWindowEx(
        NULL,
        L"3RVX", L"3RVX",
        NULL, NULL, NULL, //your boat, gently down the stream
        NULL, NULL, HWND_MESSAGE, NULL, hInstance, NULL);

    return hWnd;
}

LRESULT CALLBACK WndProc(
    HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

    if (message == MSG_VOLCHNG) {
        printf("Volume level: %.0f\n", ca->Volume() * 100.0f);
    }

    if (message == MSG_DEVCHNG) {
        printf("Device change detected.\n");
        ca->ReattachDefaultDevice();
    }

    if (message == WM_3RVX_CONTROL) {
        switch (wParam) {
        case MSG_LOAD:
            Init();
            break;

        case 101:
            printf("%x\n", lParam);
            break;
        }
    }

    if (message == WM_HOTKEY) {
        printf("Hotkey: %d\n", (int) wParam);
    }

    if (message == WM_WTSSESSION_CHANGE) {
        printf("session change\n");
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}<commit_msg>Test meter window<commit_after>#include "3RVX.h"
#include "Controllers\Volume\IVolume.h"
#include "Controllers\Volume\CoreAudio.h"
#include "LayeredWnd\LayeredWnd.h"
#include "MeterWnd\Meters\HorizontalBar.h"
#include "MeterWnd\Meters\HorizontalEndcap.h"
#include "MeterWnd\MeterWnd.h"
#include "MeterWnd\Meter.h"
#include <Wtsapi32.h>

int APIENTRY
wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow) {
    using namespace Gdiplus;

    hInst = hInstance;

    GdiplusStartupInput gdiplusStartupInput;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    mainWnd = CreateMainWnd(hInstance);
    if (mainWnd == NULL)
        return EXIT_FAILURE;

    AllocConsole();
    FILE *in, *out, *err;
    freopen_s(&in, "CONIN$", "r", stdin);
    freopen_s(&out, "CONOUT$", "w", stdout);
    freopen_s(&err, "CONOUT$", "w", stderr);

    printf("Starting...\n");

    HRESULT hr = CoInitializeEx(NULL,
        COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    /* Tell the program to initialize */
    PostMessage(mainWnd, WM_3RVX_CONTROL, MSG_LOAD, NULL);

    /* Start the event loop */
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    GdiplusShutdown(gdiplusToken);
    return (int)msg.wParam;
}

void Init() {
    ca = new CoreAudio(mainWnd);
    ca->Init();

    Meter *m = new HorizontalEndcap();
    std::wstring meterbmp(L"meter.png");
    m->SetBitmap(Gdiplus::Bitmap::FromFile(meterbmp.c_str(), false));
    m->Init();
    m->SetLocation(71, 29);
    m->SetUnits(28);
    MeterWnd *mW = new MeterWnd(hInst, L"testtest", L"what what");
    mW->AddMeter(m);
    std::wstring bgbmp(L"bg.png");
    mW->SetBackgroundImage(Gdiplus::Bitmap::FromFile(bgbmp.c_str(), true));
    mW->SetMeters(0.35);
    mW->Update();
    mW->Show();

    WTSRegisterSessionNotification(mainWnd, NOTIFY_FOR_THIS_SESSION);

    HotkeyManager *hkManager = HotkeyManager::Instance();
    hkManager->Register(mainWnd, HKM_MOD_WIN + VK_BACK);
    hkManager->Register(mainWnd, HKM_MOD_WIN + HKM_MOUSE_WHUP);
}

HWND CreateMainWnd(HINSTANCE hInstance) {
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = NULL;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = NULL;
    wcex.cbWndExtra = NULL;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"3RVX";
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    if (!RegisterClassEx(&wcex)) {
        return NULL;
    }

    HWND hWnd = CreateWindowEx(
        NULL,
        L"3RVX", L"3RVX",
        NULL, NULL, NULL, //your boat, gently down the stream
        NULL, NULL, HWND_MESSAGE, NULL, hInstance, NULL);

    return hWnd;
}

LRESULT CALLBACK WndProc(
    HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

    if (message == MSG_VOLCHNG) {
        printf("Volume level: %.0f\n", ca->Volume() * 100.0f);
    }

    if (message == MSG_DEVCHNG) {
        printf("Device change detected.\n");
        ca->ReattachDefaultDevice();
    }

    if (message == WM_3RVX_CONTROL) {
        switch (wParam) {
        case MSG_LOAD:
            Init();
            break;

        case 101:
            printf("%x\n", lParam);
            break;
        }
    }

    if (message == WM_HOTKEY) {
        printf("Hotkey: %d\n", (int) wParam);
    }

    if (message == WM_WTSSESSION_CHANGE) {
        printf("session change\n");
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}<|endoftext|>


<commit_before>#include "Engine.h"
#include "Game.h"
#include "ObjectDummy.h"
#include "BodyRigid.h"
#include "BodyDummy.h"

#include "Physics.h"
#include "ShapeCapsule.h"
#include "ActorBase.h"
#include "Visualizer.h"
#include "sys/SysControl.h"

#ifdef MEMORY_INFO
#define new new(__FILE__, __LINE__)
#endif // MEMORY_INFO

using namespace MathLib;

/*
*/
#define ACTOR_BASE_IFPS             (1.0f / 60.0f)
#define ACTOR_BASE_CLAMP            89.9f
#define ACTOR_BASE_COLLISIONS       4

/*
*/

CActorBase::CActorBase()
{
	m_vUp = vec3(0.0f, 0.0f, 1.0f);
	m_pObject = new CObjectDummy();
	m_pDummy = new CBodyDummy();
	m_pShape = new CShapeCapsule(1.0f, 1.0f);

	m_nFlush = 0;
	m_vPosition = Vec3_zero;
	m_vVelocity = Vec3_zero;
	m_fPhiAngle = 0.0f;			//б		άƽϵУֱYķX֮ļн
	m_fThetaAngle = 0.0f;			//λǣ뵱ǰ˳ʱ߹ĽǶ

	for (int i = 0; i < NUM_STATES; i++)
	{
		m_pStates[i] = 0;
		m_pTimes[i] = 0.0f;
	}

	m_pDummy->SetEnabled(1);
	m_pObject->SetBody(NULL);
	m_pObject->SetBody(m_pDummy);
	m_pShape->SetBody(NULL);
	m_pShape->SetBody(m_pDummy);

	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_pShape->SetRestitution(0.0f);
	m_pShape->SetCollisionMask(2);

	SetEnabled(1);
	SetViewDirection(vec3(0.0f,1.0f,0.0f));
	SetCollision(1);
	SetCollisionRadius(0.3f);
	SetCollisionHeight(1.0f);
	SetFriction(2.0f);
	SetMinVelocity(2.0f);
	SetMaxVelocity(4.0f);
	SetAcceleration(8.0f);
	SetDamping(8.0f);
	SetJumping(1.5f);

	SetGround(0);
	SetCeiling(0);

}
CActorBase::~CActorBase()
{
	m_pDummy->SetObject(NULL);
	delete m_pObject;
	delete m_pDummy;
}

void CActorBase::SetEnabled(int enable)
{
	m_nEnable = enable;
	m_pDummy->SetEnabled(m_nEnable);
}
int CActorBase::IsEnabled() const
{
	return m_nEnable;
}
void CActorBase::Update(float ifps)
{
	if (!m_nEnable)
	{
		return;
	}
	// impulse
	vec3 impulse = vec3_zero;

	// ortho basis
	vec3 tangent, binormal;
	OrthoBasis(m_vUp, tangent, binormal);
	// current basis
	vec3 x = quat(m_vUp, -m_fPhiAngle) * binormal;
	vec3 y = Normalize(Cross(m_vUp, x));
	vec3 z = Normalize(Cross(x, y));
	// handle states
	Update_States(1, ifps);

	// old velocity
	float x_velocity = Dot(x, m_vVelocity);
	float y_velocity = Dot(y, m_vVelocity);
	float z_velocity = Dot(z, m_vVelocity);

	// movement
	if (m_pStates[STATE_FORWARD]) impulse += x;
	if (m_pStates[STATE_BACKWARD]) impulse -= x;
	if (m_pStates[STATE_MOVE_LEFT]) impulse += y;
	if (m_pStates[STATE_MOVE_RIGHT]) impulse -= y;
	impulse.normalize();
	// velocity
	if (m_pStates[STATE_RUN]) impulse *= m_fMaxVelocity;
	else impulse *= m_fMinVelocity;

	// jump
	if (m_pStates[STATE_JUMP] == STATE_BEGIN)
	{
		impulse += z * CMathCore::Sqrt(2.0f * 9.8f * m_fJumping) / (m_fAcceleration * ifps);
	}

	// rotate velocity
	if (GetGround())
	{
		m_vVelocity = x * x_velocity + y * y_velocity + z * z_velocity;
	}
	// time
	float time = ifps * g_Engine.pPhysics->GetScale();
	// target velocity
	float target_velocity = Length(vec2(Dot(x, impulse), Dot(y, impulse)));

	// penetration tolerance
	float penetration = g_Engine.pPhysics->GetPenetrationTolerance();
	float penetration_2 = penetration * 2.0f;

	// frozen linear velocity
	float frozen_velocity = g_Engine.pPhysics->GetFrozenLinearVelocity();

	// friction
	float friction = 0.0f;
	if (target_velocity < EPSILON)
	{
		friction = m_fFriction;
	}

	// clear collision flags
	if (GetCollision())
	{
		m_nGround = 0;
		m_nCeiling = 0;
	}

	// movement
	do
	{
		// adaptive time step
		float ifps = Min(time, ACTOR_BASE_IFPS);
		time -= ifps;
		// save old velocity
		float old_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));

		// integrate velocity
		m_vVelocity += impulse * (m_fAcceleration * ifps);
		m_vVelocity += g_Engine.pPhysics->GetGravity() * ifps;

		// damping
		float current_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));
		if (target_velocity < EPSILON || current_velocity > target_velocity)
		{
			m_vVelocity = (x * Dot(x, m_vVelocity) + y * Dot(y, m_vVelocity)) * CMathCore::Exp(-m_fDamping * ifps) + z * Dot(z, m_vVelocity);
		}

		// clamp maximum velocity
		current_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));

		if (current_velocity > old_velocity)
		{
			if (current_velocity > target_velocity)
			{
				m_vVelocity = (x * Dot(x, m_vVelocity) + y * Dot(y, m_vVelocity)) * target_velocity / current_velocity + z * Dot(z, m_vVelocity);
			}
		}
		// integrate position
		//m_vPosition += Vec3(m_vVelocity * ifps);
		if (GetCollision())
		{
			// get collision
			vec3 tangent, binormal;
			const Vec3 *caps = m_pShape->GetCaps();

		}
	}

}<commit_msg>Signed-off-by: mrlitong <litongtongxue@gmail.com><commit_after>#include "Engine.h"
#include "Game.h"
#include "ObjectDummy.h"
#include "BodyRigid.h"
#include "BodyDummy.h"

#include "Physics.h"
#include "ShapeCapsule.h"
#include "ActorBase.h"
#include "Visualizer.h"
#include "sys/SysControl.h"

#ifdef MEMORY_INFO
#define new new(__FILE__, __LINE__)
#endif // MEMORY_INFO

using namespace MathLib;

/*
*/
#define ACTOR_BASE_IFPS             (1.0f / 60.0f)
#define ACTOR_BASE_CLAMP            89.9f
#define ACTOR_BASE_COLLISIONS       4

/*
*/

CActorBase::CActorBase()
{
	m_vUp = vec3(0.0f, 0.0f, 1.0f);
	m_pObject = new CObjectDummy();
	m_pDummy = new CBodyDummy();
	m_pShape = new CShapeCapsule(1.0f, 1.0f);

	m_nFlush = 0;
	m_vPosition = Vec3_zero;
	m_vVelocity = Vec3_zero;
	m_fPhiAngle = 0.0f;			//б		άƽϵУֱYķX֮ļн
	m_fThetaAngle = 0.0f;			//λǣ뵱ǰ˳ʱ߹ĽǶ

	for (int i = 0; i < NUM_STATES; i++)
	{
		m_pStates[i] = 0;
		m_pTimes[i] = 0.0f;
	}

	m_pDummy->SetEnabled(1);
	m_pObject->SetBody(NULL);
	m_pObject->SetBody(m_pDummy);
	m_pShape->SetBody(NULL);
	m_pShape->SetBody(m_pDummy);

	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_pShape->SetRestitution(0.0f);
	m_pShape->SetCollisionMask(2);

	SetEnabled(1);
	SetViewDirection(vec3(0.0f,1.0f,0.0f));
	SetCollision(1);
	SetCollisionRadius(0.3f);
	SetCollisionHeight(1.0f);
	SetFriction(2.0f);
	SetMinVelocity(2.0f);
	SetMaxVelocity(4.0f);
	SetAcceleration(8.0f);
	SetDamping(8.0f);
	SetJumping(1.5f);

	SetGround(0);
	SetCeiling(0);

}
CActorBase::~CActorBase()
{
	m_pDummy->SetObject(NULL);
	delete m_pObject;
	delete m_pDummy;
}

void CActorBase::SetEnabled(int enable)
{
	m_nEnable = enable;
	m_pDummy->SetEnabled(m_nEnable);
}
int CActorBase::IsEnabled() const
{
	return m_nEnable;
}
void CActorBase::Update(float ifps)
{
	if (!m_nEnable)
	{
		return;
	}
	// impulse
	vec3 impulse = vec3_zero;

	// ortho basis
	vec3 tangent, binormal;
	OrthoBasis(m_vUp, tangent, binormal);
	// current basis
	vec3 x = quat(m_vUp, -m_fPhiAngle) * binormal;
	vec3 y = Normalize(Cross(m_vUp, x));
	vec3 z = Normalize(Cross(x, y));
	// handle states
	Update_States(1, ifps);

	// old velocity
	float x_velocity = Dot(x, m_vVelocity);
	float y_velocity = Dot(y, m_vVelocity);
	float z_velocity = Dot(z, m_vVelocity);

	// movement
	if (m_pStates[STATE_FORWARD]) impulse += x;
	if (m_pStates[STATE_BACKWARD]) impulse -= x;
	if (m_pStates[STATE_MOVE_LEFT]) impulse += y;
	if (m_pStates[STATE_MOVE_RIGHT]) impulse -= y;
	impulse.normalize();
	// velocity
	if (m_pStates[STATE_RUN]) impulse *= m_fMaxVelocity;
	else impulse *= m_fMinVelocity;

	// jump
	if (m_pStates[STATE_JUMP] == STATE_BEGIN)
	{
		impulse += z * CMathCore::Sqrt(2.0f * 9.8f * m_fJumping) / (m_fAcceleration * ifps);
	}

	// rotate velocity
	if (GetGround())
	{
		m_vVelocity = x * x_velocity + y * y_velocity + z * z_velocity;
	}
	// time
	float time = ifps * g_Engine.pPhysics->GetScale();
	// target velocity
	float target_velocity = Length(vec2(Dot(x, impulse), Dot(y, impulse)));

	// penetration tolerance
	float penetration = g_Engine.pPhysics->GetPenetrationTolerance();
	float penetration_2 = penetration * 2.0f;

	// frozen linear velocity
	float frozen_velocity = g_Engine.pPhysics->GetFrozenLinearVelocity();

	// friction
	float friction = 0.0f;
	if (target_velocity < EPSILON)
	{
		friction = m_fFriction;
	}

	// clear collision flags
	if (GetCollision())
	{
		m_nGround = 0;
		m_nCeiling = 0;
	}

	// movement
	do
	{
		// adaptive time step
		float ifps = Min(time, ACTOR_BASE_IFPS);
		time -= ifps;
		// save old velocity
		float old_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));

		// integrate velocity
		m_vVelocity += impulse * (m_fAcceleration * ifps);
		m_vVelocity += g_Engine.pPhysics->GetGravity() * ifps;

		// damping
		float current_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));
		if (target_velocity < EPSILON || current_velocity > target_velocity)
		{
			m_vVelocity = (x * Dot(x, m_vVelocity) + y * Dot(y, m_vVelocity)) * CMathCore::Exp(-m_fDamping * ifps) + z * Dot(z, m_vVelocity);
		}

		// clamp maximum velocity
		current_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));

		if (current_velocity > old_velocity)
		{
			if (current_velocity > target_velocity)
			{
				m_vVelocity = (x * Dot(x, m_vVelocity) + y * Dot(y, m_vVelocity)) * target_velocity / current_velocity + z * Dot(z, m_vVelocity);
			}
		}
		// integrate position
		//m_vPosition += Vec3(m_vVelocity * ifps);
		if (GetCollision())
		{
			// get collision
			vec3 tangent, binormal;
			const Vec3 *caps = m_pShape->GetCaps();
			for (int i = 0; i < ACTOR_BASE_COLLISIONS; i++)
			{

			}
		}
	}

}<|endoftext|>


<commit_before>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief %Object commands.
@ingroup cmd_object
*/

#pragma once

#include <Hord/config.hpp>
#include <Hord/String.hpp>
#include <Hord/Data/Defs.hpp>
#include <Hord/Data/Table.hpp>
#include <Hord/Object/Defs.hpp>
#include <Hord/Cmd/Defs.hpp>
#include <Hord/Cmd/Unit.hpp>

namespace Hord {
namespace Cmd {
namespace Object {

// Forward declarations
class SetSlug;
class SetMetaField;
class RenameMetaField;
class RemoveMetaField;

/**
	@addtogroup cmd_object
	@{
*/

/**
	Set slug command.
*/
class SetSlug final
	: public Cmd::Unit<SetSlug>
{
	HORD_CMD_IMPL_BOILERPLATE(
		SetSlug,
		"Cmd::Object::SetSlug"
	);

public:
/** @name Operations */ /// @{
	/**
		Set slug.

		@param object Object to modify.
		@param new_slug New slug.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		String new_slug
	) noexcept;
/// @}
};

/**
	Set MetaField value command.
*/
class SetMetaField final
	: public Cmd::Unit<SetMetaField>
{
	HORD_CMD_IMPL_BOILERPLATE(
		SetMetaField,
		"Cmd::Object::SetMetaField"
	);

private:
	bool m_created{false};

public:
/** @name Properties */ /// @{
	/**
		Get whether a new field was created.
	*/
	bool created() const noexcept {
		return m_created;
	}
/// @}

/** @name Operations */ /// @{
	/**
		Set field value by index.

		@param object Object to modify.
		@param index Index of field.
		@param new_value New value for field.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		unsigned const index,
		Data::ValueRef const& new_value
	) noexcept;

	/**
		Set field value by name.

		@param object Object to modify.
		@param name Name of field.
		@param new_value New value for field.
		@param create Whether to create the field if it does not exist.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		String const& name,
		Data::ValueRef const& new_value,
		bool const create = false
	) noexcept;
/// @}
};

/**
	Rename MetaField command.
*/
class RenameMetaField final
	: public Cmd::Unit<RenameMetaField>
{
	HORD_CMD_IMPL_BOILERPLATE(
		RenameMetaField,
		"Cmd::Object::RenameMetaField"
	);

private:
	Cmd::Result
	set_name(
		Hord::Object::Unit& object,
		Hord::Data::Table::Iterator& it,
		String const& new_name
	);

public:
/** @name Operations */ /// @{
	/**
		Rename field by index.

		@param object Object to modify.
		@param index Index of field.
		@param new_name New name.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		unsigned const index,
		String const& new_name
	) noexcept;

	/**
		Rename field by name.

		@param object Object to modify.
		@param old_name Name of field.
		@param new_name New name.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		String const& old_name,
		String const& new_name
	) noexcept;
/// @}
};

/**
	Rename MetaField command.
*/
class RemoveMetaField final
	: public Cmd::Unit<RemoveMetaField>
{
	HORD_CMD_IMPL_BOILERPLATE(
		RemoveMetaField,
		"Cmd::Object::RemoveMetaField"
	);

public:
/** @name Operations */ /// @{
	/**
		Remove field by index.

		@param object Object to modify.
		@param index Index of field.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		unsigned const index
	) noexcept;

	/**
		Remove field by name.

		@param object Object to modify.
		@param name Name of field.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		String const& name
	) noexcept;
/// @}
};

/** @} */ // end of doc-group cmd_object

} // namespace Object

/** @cond INTERNAL */
HORD_CMD_IMPL_ENSURE_TRAITS(Cmd::Object::SetMetaField);
HORD_CMD_IMPL_ENSURE_TRAITS(Cmd::Object::RenameMetaField);
HORD_CMD_IMPL_ENSURE_TRAITS(Cmd::Object::RemoveMetaField);
/** @endcond */ // INTERNAL

} // namespace Cmd
} // namespace Hord
<commit_msg>Cmd::Object::SetMetaField: defaulted create param to true.<commit_after>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief %Object commands.
@ingroup cmd_object
*/

#pragma once

#include <Hord/config.hpp>
#include <Hord/String.hpp>
#include <Hord/Data/Defs.hpp>
#include <Hord/Data/Table.hpp>
#include <Hord/Object/Defs.hpp>
#include <Hord/Cmd/Defs.hpp>
#include <Hord/Cmd/Unit.hpp>

namespace Hord {
namespace Cmd {
namespace Object {

// Forward declarations
class SetSlug;
class SetMetaField;
class RenameMetaField;
class RemoveMetaField;

/**
	@addtogroup cmd_object
	@{
*/

/**
	Set slug command.
*/
class SetSlug final
	: public Cmd::Unit<SetSlug>
{
	HORD_CMD_IMPL_BOILERPLATE(
		SetSlug,
		"Cmd::Object::SetSlug"
	);

public:
/** @name Operations */ /// @{
	/**
		Set slug.

		@param object Object to modify.
		@param new_slug New slug.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		String new_slug
	) noexcept;
/// @}
};

/**
	Set MetaField value command.
*/
class SetMetaField final
	: public Cmd::Unit<SetMetaField>
{
	HORD_CMD_IMPL_BOILERPLATE(
		SetMetaField,
		"Cmd::Object::SetMetaField"
	);

private:
	bool m_created{false};

public:
/** @name Properties */ /// @{
	/**
		Get whether a new field was created.
	*/
	bool created() const noexcept {
		return m_created;
	}
/// @}

/** @name Operations */ /// @{
	/**
		Set field value by index.

		@param object Object to modify.
		@param index Index of field.
		@param new_value New value for field.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		unsigned const index,
		Data::ValueRef const& new_value
	) noexcept;

	/**
		Set field value by name.

		@param object Object to modify.
		@param name Name of field.
		@param new_value New value for field.
		@param create Whether to create the field if it does not exist.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		String const& name,
		Data::ValueRef const& new_value,
		bool const create = true
	) noexcept;
/// @}
};

/**
	Rename MetaField command.
*/
class RenameMetaField final
	: public Cmd::Unit<RenameMetaField>
{
	HORD_CMD_IMPL_BOILERPLATE(
		RenameMetaField,
		"Cmd::Object::RenameMetaField"
	);

private:
	Cmd::Result
	set_name(
		Hord::Object::Unit& object,
		Hord::Data::Table::Iterator& it,
		String const& new_name
	);

public:
/** @name Operations */ /// @{
	/**
		Rename field by index.

		@param object Object to modify.
		@param index Index of field.
		@param new_name New name.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		unsigned const index,
		String const& new_name
	) noexcept;

	/**
		Rename field by name.

		@param object Object to modify.
		@param old_name Name of field.
		@param new_name New name.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		String const& old_name,
		String const& new_name
	) noexcept;
/// @}
};

/**
	Rename MetaField command.
*/
class RemoveMetaField final
	: public Cmd::Unit<RemoveMetaField>
{
	HORD_CMD_IMPL_BOILERPLATE(
		RemoveMetaField,
		"Cmd::Object::RemoveMetaField"
	);

public:
/** @name Operations */ /// @{
	/**
		Remove field by index.

		@param object Object to modify.
		@param index Index of field.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		unsigned const index
	) noexcept;

	/**
		Remove field by name.

		@param object Object to modify.
		@param name Name of field.
	*/
	exec_result_type
	operator()(
		Hord::Object::Unit& object,
		String const& name
	) noexcept;
/// @}
};

/** @} */ // end of doc-group cmd_object

} // namespace Object

/** @cond INTERNAL */
HORD_CMD_IMPL_ENSURE_TRAITS(Cmd::Object::SetMetaField);
HORD_CMD_IMPL_ENSURE_TRAITS(Cmd::Object::RenameMetaField);
HORD_CMD_IMPL_ENSURE_TRAITS(Cmd::Object::RemoveMetaField);
/** @endcond */ // INTERNAL

} // namespace Cmd
} // namespace Hord
<|endoftext|>


<commit_before>//g++ -I/usr/include/libxml2 verifyxmllicense.cpp -lcrypto++ -lxml2 -o verifyxmllicense

#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

int main()
{

    xmlDocPtr doc = xmlReadFile("xmllicense.xml", NULL, 0);
    if (doc == NULL)
	{
        fprintf(stderr, "Failed to parse xmllicense.xml");
		exit(0);
    }
    xmlFreeDoc(doc);

    //Cleanup function for the XML library.
    xmlCleanupParser();

	//this is to debug memory for regression tests
    xmlMemoryDump();

}
<commit_msg>Iterate over tree<commit_after>//g++ -I/usr/include/libxml2 verifyxmllicense.cpp -lcrypto++ -lxml2 -o verifyxmllicense

#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

int Verify(const char *filename)
{
	//parse the file and get the DOM
	xmlDoc *doc = xmlReadFile(filename, NULL, 0);

	if (doc == NULL)
	{
		printf("error: could not parse file\n");
		return 0;
	}

	//Get the root element node
	xmlNode *root_element = xmlDocGetRootElement(doc);

	for (xmlNode *rootEl = root_element; rootEl; rootEl = rootEl->next)
	{
		if (rootEl->type != XML_ELEMENT_NODE) continue;
		printf("node type: Element, name: %s\n", rootEl->name);

		for (xmlNode *el = rootEl->children; el; el = el->next)
		{
			if (el->type != XML_ELEMENT_NODE) continue;
			printf("node type: Element, name: %s\n", el->name);

			for (xmlNode *el2 = el->children; el2; el2 = el2->next)
			{
				if (el2->type != XML_ELEMENT_NODE) continue;
				printf("node type: Element, name: %s\n", el2->name);

			}
		}
	}

	//free the document
	xmlFreeDoc(doc);

	return 1;

}

int main()
{

	Verify("xmllicense.xml");

}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include <membership.h>

#include <osquery/core.h>
#include <osquery/logger.h>
#include <osquery/tables.h>
#include <osquery/sql.h>

#include "osquery/tables/system/darwin/iokit_utils.h"

namespace osquery {
namespace tables {

// AES-XTS is the only block algorithm supported by FileVault2
// https://opensource.apple.com/source/xnu/xnu-2782.1.97/libkern/crypto/corecrypto_aesxts.c
const std::string kEncryptionType = "AES-XTS";
const std::string kDeviceNamePrefix = "/dev/";

// kCoreStorageIsEncryptedKey is not publicly defined
// or documented because CoreStorage is a private framework
#define kCoreStorageIsEncryptedKey_ "CoreStorage Encrypted"
#define kIODeviceTreeChosenPath_ "IODeviceTree:/chosen"

Status genUnlockIdent(CFDataRef& uuid) {
  auto chosen =
      IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreeChosenPath_);
  if (chosen == MACH_PORT_NULL) {
    return Status(1, "Could not open IOKit DeviceTree");
  }

  CFMutableDictionaryRef properties = nullptr;
  auto kr = IORegistryEntryCreateCFProperties(
      chosen, &properties, kCFAllocatorDefault, kNilOptions);
  IOObjectRelease(chosen);

  if (kr != KERN_SUCCESS) {
    return Status(1, "Could not get IOKit chosen properties");
  }

  if (properties == nullptr) {
    return Status(1, "Could not load IOKit properties");
  }

  CFTypeRef unlock_ident = nullptr;
  if (CFDictionaryGetValueIfPresent(
          properties, CFSTR("efilogin-unlock-ident"), &unlock_ident)) {
    if (CFGetTypeID(unlock_ident) != CFDataGetTypeID()) {
      return Status(1, "Unexpected data type for unlock ident");
    }
    uuid = (CFDataRef)unlock_ident;
    CFRelease(properties);
    return Status(0, "ok");
  }

  return Status(1, "Could not get unlock ident");
}

Status genUid(id_t& uid) {
  CFDataRef uuid = nullptr;
  if (!genUnlockIdent(uuid).ok()) {
    return Status(1, "Could not get unlock ident");
  }

  char buffer[37] = {0};
  CFDataGetBytes(uuid, CFRangeMake(0, CFDataGetLength(uuid)), (UInt8*)buffer);

  uuid_t uuidT;
  if (uuid_parse(buffer, uuidT) != 0) {
    return Status(1, "Could not parse UUID");
  }

  // id_type >=0 are all valid id types
  int id_type = -1;
  if (mbr_uuid_to_id(uuidT, &uid, &id_type) != 0 && id_type != ID_TYPE_UID) {
    return Status(1, "Could not get uid from uuid");
  }

  return Status(0, "ok");
}

void genFDEStatusForBSDName(const std::string& bsd_name,
                            const std::string& uuid,
                            QueryData& results) {

  auto matching_dict =
      IOBSDNameMatching(kIOMasterPortDefault, kNilOptions, bsd_name.c_str());
  if (matching_dict == nullptr) {
    return;
  }

  auto service =
      IOServiceGetMatchingService(kIOMasterPortDefault, matching_dict);
  if (!service) {
    return;
  }

  CFMutableDictionaryRef properties;
  if (IORegistryEntryCreateCFProperties(
          service, &properties, kCFAllocatorDefault, kNilOptions) !=
      KERN_SUCCESS) {
    IOObjectRelease(service);
    return;
  }

  Row r;
  r["name"] = kDeviceNamePrefix + bsd_name;
  r["uuid"] = uuid;

  auto encrypted = getIOKitProperty(properties, kCoreStorageIsEncryptedKey_);
  if (encrypted.empty()) {
    r["encrypted"] = "0";
  } else {
    r["encrypted"] = encrypted;
    id_t uid;
    if (genUid(uid).ok()) {
      r["uid"] = BIGINT(uid);
    }
  }
  r["type"] = (r.at("encrypted") == "1") ? kEncryptionType : std::string();

  results.push_back(r);
  CFRelease(properties);
  IOObjectRelease(service);
}

QueryData genFDEStatus(QueryContext& context) {
  QueryData results;

  auto block_devices = SQL::selectAllFrom("block_devices");

  for (const auto& row : block_devices) {
    const auto bsd_name = row.at("name").substr(kDeviceNamePrefix.size());
    genFDEStatusForBSDName(bsd_name, row.at("uuid"), results);
  }

  return results;
}
}
}
<commit_msg>Create copy of UUID data so that we have a value and not a reference before releasing the properties<commit_after>/*
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include <membership.h>

#include <osquery/core.h>
#include <osquery/logger.h>
#include <osquery/tables.h>
#include <osquery/sql.h>

#include "osquery/tables/system/darwin/iokit_utils.h"

namespace osquery {
namespace tables {

// AES-XTS is the only block algorithm supported by FileVault2
// https://opensource.apple.com/source/xnu/xnu-2782.1.97/libkern/crypto/corecrypto_aesxts.c
const std::string kEncryptionType = "AES-XTS";
const std::string kDeviceNamePrefix = "/dev/";

// kCoreStorageIsEncryptedKey is not publicly defined
// or documented because CoreStorage is a private framework
#define kCoreStorageIsEncryptedKey_ "CoreStorage Encrypted"
#define kIODeviceTreeChosenPath_ "IODeviceTree:/chosen"

Status genUnlockIdent(CFDataRef& uuid) {
  auto chosen =
      IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreeChosenPath_);
  if (chosen == MACH_PORT_NULL) {
    return Status(1, "Could not open IOKit DeviceTree");
  }

  CFMutableDictionaryRef properties = nullptr;
  auto kr = IORegistryEntryCreateCFProperties(
      chosen, &properties, kCFAllocatorDefault, kNilOptions);
  IOObjectRelease(chosen);

  if (kr != KERN_SUCCESS) {
    return Status(1, "Could not get IOKit chosen properties");
  }

  if (properties == nullptr) {
    return Status(1, "Could not load IOKit properties");
  }

  CFTypeRef unlock_ident = nullptr;
  if (CFDictionaryGetValueIfPresent(
          properties, CFSTR("efilogin-unlock-ident"), &unlock_ident)) {
    if (CFGetTypeID(unlock_ident) != CFDataGetTypeID()) {
      return Status(1, "Unexpected data type for unlock ident");
    }
    uuid = CFDataCreateCopy(kCFAllocatorDefault, (CFDataRef)unlock_ident);
    if (uuid == nullptr) {
      return Status(1, "Could not get UUID");
    }
    CFRelease(properties);
    return Status(0, "ok");
  }

  return Status(1, "Could not get unlock ident");
}

Status genUid(id_t& uid) {
  CFDataRef uuid = nullptr;
  if (!genUnlockIdent(uuid).ok()) {
    return Status(1, "Could not get unlock ident");
  }

  char buffer[37] = {0};
  CFDataGetBytes(uuid, CFRangeMake(0, CFDataGetLength(uuid)), (UInt8*)buffer);

  uuid_t uuidT;
  if (uuid_parse(buffer, uuidT) != 0) {
    return Status(1, "Could not parse UUID");
  }

  // id_type >=0 are all valid id types
  int id_type = -1;
  if (mbr_uuid_to_id(uuidT, &uid, &id_type) != 0 && id_type != ID_TYPE_UID) {
    return Status(1, "Could not get uid from uuid");
  }

  return Status(0, "ok");
}

void genFDEStatusForBSDName(const std::string& bsd_name,
                            const std::string& uuid,
                            QueryData& results) {

  auto matching_dict =
      IOBSDNameMatching(kIOMasterPortDefault, kNilOptions, bsd_name.c_str());
  if (matching_dict == nullptr) {
    return;
  }

  auto service =
      IOServiceGetMatchingService(kIOMasterPortDefault, matching_dict);
  if (!service) {
    return;
  }

  CFMutableDictionaryRef properties;
  if (IORegistryEntryCreateCFProperties(
          service, &properties, kCFAllocatorDefault, kNilOptions) !=
      KERN_SUCCESS) {
    IOObjectRelease(service);
    return;
  }

  Row r;
  r["name"] = kDeviceNamePrefix + bsd_name;
  r["uuid"] = uuid;

  auto encrypted = getIOKitProperty(properties, kCoreStorageIsEncryptedKey_);
  if (encrypted.empty()) {
    r["encrypted"] = "0";
  } else {
    r["encrypted"] = encrypted;
    id_t uid;
    if (genUid(uid).ok()) {
      r["uid"] = BIGINT(uid);
    }
  }
  r["type"] = (r.at("encrypted") == "1") ? kEncryptionType : std::string();

  results.push_back(r);
  CFRelease(properties);
  IOObjectRelease(service);
}

QueryData genFDEStatus(QueryContext& context) {
  QueryData results;

  auto block_devices = SQL::selectAllFrom("block_devices");

  for (const auto& row : block_devices) {
    const auto bsd_name = row.at("name").substr(kDeviceNamePrefix.size());
    genFDEStatusForBSDName(bsd_name, row.at("uuid"), results);
  }

  return results;
}
}
}
<|endoftext|>