⛏️ index : haiku.git

/*
 * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Axel Dörfler, axeld@pinc-software.de
 *		Michael Lotz <mmlr@mlotz.ch>
 */


#include "DriverSettingsMessageAdapter.h"

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#include <File.h>
#include <String.h>


DriverSettingsConverter::DriverSettingsConverter()
{
}


DriverSettingsConverter::~DriverSettingsConverter()
{
}


status_t
DriverSettingsConverter::ConvertFromDriverSettings(
	const driver_parameter& parameter, const char* name, int32 index,
	uint32 type, BMessage& target)
{
	return B_NOT_SUPPORTED;
}


status_t
DriverSettingsConverter::ConvertEmptyFromDriverSettings(
	const driver_parameter& parameter, const char* name, uint32 type,
	BMessage& target)
{
	return B_NOT_SUPPORTED;
}


status_t
DriverSettingsConverter::ConvertToDriverSettings(const BMessage& source,
	const char* name, int32 index, uint32 type, BString& value)
{
	return B_NOT_SUPPORTED;
}


// #pragma mark -


DriverSettingsMessageAdapter::DriverSettingsMessageAdapter()
{
}


DriverSettingsMessageAdapter::~DriverSettingsMessageAdapter()
{
}


status_t
DriverSettingsMessageAdapter::ConvertFromDriverSettings(
	const driver_settings& settings, const settings_template* settingsTemplate,
	BMessage& message)
{
	message.MakeEmpty();

	for (int32 i = 0; i < settings.parameter_count; i++) {
		status_t status = _ConvertFromDriverParameter(settings.parameters[i],
			settingsTemplate, message);
		if (status == B_BAD_VALUE) {
			// ignore unknown entries
			continue;
		}
		if (status != B_OK)
			return status;
	}

	return B_OK;
}


status_t
DriverSettingsMessageAdapter::ConvertFromDriverSettings(const char* path,
	const settings_template* settingsTemplate, BMessage& message)
{
	void* handle = load_driver_settings(path);
	if (handle == NULL)
		return B_ENTRY_NOT_FOUND;

	const driver_settings* settings = get_driver_settings(handle);
	status_t status;
	if (settings != NULL) {
		status = ConvertFromDriverSettings(*settings, settingsTemplate,
			message);
	} else
		status = B_BAD_DATA;

	unload_driver_settings(handle);
	return status;
}


status_t
DriverSettingsMessageAdapter::ConvertToDriverSettings(
	const settings_template* settingsTemplate, BString& settings,
	const BMessage& message)
{
	int32 index = 0;
	char *name = NULL;
	type_code type;
	int32 count = 0;

	while (message.GetInfo(B_ANY_TYPE, index++, &name, &type, &count) == B_OK) {
		status_t result = _AppendSettings(settingsTemplate, settings, message,
			name, type, count);
		if (result != B_OK)
			return result;
	}

	return B_OK;
}


status_t
DriverSettingsMessageAdapter::ConvertToDriverSettings(const char* path,
	const settings_template* settingsTemplate, const BMessage& message)
{
	BString settings;
	status_t status = ConvertToDriverSettings(settingsTemplate, settings,
		message);
	if (status != B_OK)
		return status;

	settings.RemoveFirst("\n");
	BFile settingsFile(path, B_WRITE_ONLY | B_ERASE_FILE | B_CREATE_FILE);

	ssize_t written = settingsFile.Write(settings.String(), settings.Length());
	if (written < 0)
		return written;

	return written == settings.Length() ? B_OK : B_ERROR;
}


// #pragma mark -


const settings_template*
DriverSettingsMessageAdapter::_FindSettingsTemplate(
	const settings_template* settingsTemplate, const char* name)
{
	const settings_template* wildcardTemplate = NULL;

	while (settingsTemplate->type != 0) {
		if (settingsTemplate->name != NULL
			&& !strcmp(name, settingsTemplate->name))
			return settingsTemplate;

		if (settingsTemplate->name == NULL)
			wildcardTemplate = settingsTemplate;
		settingsTemplate++;
	}

	return wildcardTemplate;
}


const settings_template*
DriverSettingsMessageAdapter::_FindParentValueTemplate(
	const settings_template* settingsTemplate)
{
	settingsTemplate = settingsTemplate->sub_template;
	if (settingsTemplate == NULL)
		return NULL;

	while (settingsTemplate->type != 0) {
		if (settingsTemplate->parent_value)
			return settingsTemplate;

		settingsTemplate++;
	}

	return NULL;
}


status_t
DriverSettingsMessageAdapter::_AddParameter(const driver_parameter& parameter,
	const settings_template& settingsTemplate, BMessage& message)
{
	const char* name = settingsTemplate.name;
	if (name == NULL)
		name = parameter.name;

	for (int32 i = 0; i < parameter.value_count; i++) {
		if (settingsTemplate.converter != NULL) {
			status_t status
				= settingsTemplate.converter->ConvertFromDriverSettings(
					parameter, name, i, settingsTemplate.type, message);
			if (status == B_OK)
				continue;
			if (status != B_NOT_SUPPORTED)
				return status;
		}

		status_t status = B_OK;

		switch (settingsTemplate.type) {
			case B_STRING_TYPE:
				status = message.AddString(name, parameter.values[i]);
				break;
			case B_INT32_TYPE:
				status = message.AddInt32(name, atoi(parameter.values[i]));
				break;
			case B_BOOL_TYPE:
			{
				bool value=!strcasecmp(parameter.values[i], "true")
					|| !strcasecmp(parameter.values[i], "on")
					|| !strcasecmp(parameter.values[i], "yes")
					|| !strcasecmp(parameter.values[i], "enabled")
					|| !strcasecmp(parameter.values[i], "1");
				status = message.AddBool(name, value);
				break;
			}
			case B_MESSAGE_TYPE:
				// Is handled outside of this method
				break;

			default:
				return B_BAD_VALUE;
		}
		if (status != B_OK)
			return status;
	}

	if (parameter.value_count == 0) {
		if (settingsTemplate.converter != NULL) {
			status_t status
				= settingsTemplate.converter->ConvertEmptyFromDriverSettings(
					parameter, name, settingsTemplate.type, message);
			if (status == B_NOT_SUPPORTED)
				return B_OK;
		} else if (settingsTemplate.type == B_BOOL_TYPE) {
			// Empty boolean parameters are always true
			return message.AddBool(name, true);
		}
	}

	return B_OK;
}


status_t
DriverSettingsMessageAdapter::_ConvertFromDriverParameter(
	const driver_parameter& parameter,
	const settings_template* settingsTemplate, BMessage& message)
{
	settingsTemplate = _FindSettingsTemplate(settingsTemplate, parameter.name);
	if (settingsTemplate == NULL) {
		// We almost silently ignore this kind of issues
		fprintf(stderr, "unknown parameter %s\n", parameter.name);
		return B_OK;
	}

	status_t status = _AddParameter(parameter, *settingsTemplate, message);
	if (status != B_OK)
		return status;

	if (settingsTemplate->type == B_MESSAGE_TYPE) {
		BMessage subMessage;
		for (int32 j = 0; j < parameter.parameter_count; j++) {
			status = _ConvertFromDriverParameter(parameter.parameters[j],
				settingsTemplate->sub_template, subMessage);
			if (status != B_OK)
				return status;
		}

		const settings_template* parentValueTemplate
			= _FindParentValueTemplate(settingsTemplate);
		if (parentValueTemplate != NULL)
			status = _AddParameter(parameter, *parentValueTemplate, subMessage);
		if (status == B_OK)
			status = message.AddMessage(parameter.name, &subMessage);
	}

	return status;
}


status_t
DriverSettingsMessageAdapter::_AppendSettings(
	const settings_template* settingsTemplate, BString& settings,
	const BMessage& message, const char* name, type_code type, int32 count,
	const char* settingName)
{
	const settings_template* valueTemplate
		= _FindSettingsTemplate(settingsTemplate, name);
	if (valueTemplate == NULL) {
		fprintf(stderr, "unknown field %s\n", name);
		return B_BAD_VALUE;
	}

	if (valueTemplate->type != type) {
		fprintf(stderr, "field type mismatch %s\n", name);
		return B_BAD_VALUE;
	}

	if (settingName == NULL)
		settingName = name;

	if (type != B_MESSAGE_TYPE) {
		settings.Append("\n");
		settings.Append(settingName);
		settings.Append("\t");
	}

	for (int32 valueIndex = 0; valueIndex < count; valueIndex++) {
		if (valueIndex > 0 && type != B_MESSAGE_TYPE)
			settings.Append(" ");

		if (valueTemplate->converter != NULL) {
			status_t status = valueTemplate->converter->ConvertToDriverSettings(
				message, name, type, valueIndex, settings);
			if (status == B_OK)
				continue;
			if (status != B_NOT_SUPPORTED)
				return status;
		}

		switch (type) {
			case B_BOOL_TYPE:
			{
				bool value;
				status_t result = message.FindBool(name, valueIndex, &value);
				if (result != B_OK)
					return result;

				settings.Append(value ? "true" : "false");
				break;
			}

			case B_STRING_TYPE:
			{
				const char* value = NULL;
				status_t result = message.FindString(name, valueIndex, &value);
				if (result != B_OK)
					return result;

				settings.Append(value);
				break;
			}

			case B_INT32_TYPE:
			{
				int32 value;
				status_t result = message.FindInt32(name, valueIndex, &value);
				if (result != B_OK)
					return result;

				char buffer[100];
				snprintf(buffer, sizeof(buffer), "%" B_PRId32, value);
				settings.Append(buffer, sizeof(buffer));
				break;
			}

			case B_MESSAGE_TYPE:
			{
				BMessage subMessage;
				status_t result = message.FindMessage(name, valueIndex,
					&subMessage);
				if (result != B_OK)
					return result;

				const settings_template* parentValueTemplate
					= _FindParentValueTemplate(valueTemplate);
				if (parentValueTemplate != NULL) {
					_AppendSettings(valueTemplate->sub_template, settings,
						subMessage, parentValueTemplate->name,
						parentValueTemplate->type, 1, name);
					subMessage.RemoveName(parentValueTemplate->name);
				}

				BString subSettings;
				ConvertToDriverSettings(valueTemplate->sub_template,
					subSettings, subMessage);
				subSettings.ReplaceAll("\n", "\n\t");
				subSettings.RemoveFirst("\n");

				if (!subSettings.IsEmpty()) {
					settings.Append(" {\n");
					settings.Append(subSettings);
					settings.Append("\n}");
				}
			}
		}
	}

	return B_OK;
}