1/*
2 * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 *		Michael Lotz <mmlr@mlotz.ch>
8 */
9
10
11#include "DriverSettingsMessageAdapter.h"
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <strings.h>
16
17#include <File.h>
18#include <String.h>
19
20
21DriverSettingsConverter::DriverSettingsConverter()
22{
23}
24
25
26DriverSettingsConverter::~DriverSettingsConverter()
27{
28}
29
30
31status_t
32DriverSettingsConverter::ConvertFromDriverSettings(
33	const driver_parameter& parameter, const char* name, int32 index,
34	uint32 type, BMessage& target)
35{
36	return B_NOT_SUPPORTED;
37}
38
39
40status_t
41DriverSettingsConverter::ConvertEmptyFromDriverSettings(
42	const driver_parameter& parameter, const char* name, uint32 type,
43	BMessage& target)
44{
45	return B_NOT_SUPPORTED;
46}
47
48
49status_t
50DriverSettingsConverter::ConvertToDriverSettings(const BMessage& source,
51	const char* name, int32 index, uint32 type, BString& value)
52{
53	return B_NOT_SUPPORTED;
54}
55
56
57// #pragma mark -
58
59
60DriverSettingsMessageAdapter::DriverSettingsMessageAdapter()
61{
62}
63
64
65DriverSettingsMessageAdapter::~DriverSettingsMessageAdapter()
66{
67}
68
69
70status_t
71DriverSettingsMessageAdapter::ConvertFromDriverSettings(
72	const driver_settings& settings, const settings_template* settingsTemplate,
73	BMessage& message)
74{
75	message.MakeEmpty();
76
77	for (int32 i = 0; i < settings.parameter_count; i++) {
78		status_t status = _ConvertFromDriverParameter(settings.parameters[i],
79			settingsTemplate, message);
80		if (status == B_BAD_VALUE) {
81			// ignore unknown entries
82			continue;
83		}
84		if (status != B_OK)
85			return status;
86	}
87
88	return B_OK;
89}
90
91
92status_t
93DriverSettingsMessageAdapter::ConvertFromDriverSettings(const char* path,
94	const settings_template* settingsTemplate, BMessage& message)
95{
96	void* handle = load_driver_settings(path);
97	if (handle == NULL)
98		return B_ENTRY_NOT_FOUND;
99
100	const driver_settings* settings = get_driver_settings(handle);
101	status_t status;
102	if (settings != NULL) {
103		status = ConvertFromDriverSettings(*settings, settingsTemplate,
104			message);
105	} else
106		status = B_BAD_DATA;
107
108	unload_driver_settings(handle);
109	return status;
110}
111
112
113status_t
114DriverSettingsMessageAdapter::ConvertToDriverSettings(
115	const settings_template* settingsTemplate, BString& settings,
116	const BMessage& message)
117{
118	int32 index = 0;
119	char *name = NULL;
120	type_code type;
121	int32 count = 0;
122
123	while (message.GetInfo(B_ANY_TYPE, index++, &name, &type, &count) == B_OK) {
124		status_t result = _AppendSettings(settingsTemplate, settings, message,
125			name, type, count);
126		if (result != B_OK)
127			return result;
128	}
129
130	return B_OK;
131}
132
133
134status_t
135DriverSettingsMessageAdapter::ConvertToDriverSettings(const char* path,
136	const settings_template* settingsTemplate, const BMessage& message)
137{
138	BString settings;
139	status_t status = ConvertToDriverSettings(settingsTemplate, settings,
140		message);
141	if (status != B_OK)
142		return status;
143
144	settings.RemoveFirst("\n");
145	BFile settingsFile(path, B_WRITE_ONLY | B_ERASE_FILE | B_CREATE_FILE);
146
147	ssize_t written = settingsFile.Write(settings.String(), settings.Length());
148	if (written < 0)
149		return written;
150
151	return written == settings.Length() ? B_OK : B_ERROR;
152}
153
154
155// #pragma mark -
156
157
158const settings_template*
159DriverSettingsMessageAdapter::_FindSettingsTemplate(
160	const settings_template* settingsTemplate, const char* name)
161{
162	const settings_template* wildcardTemplate = NULL;
163
164	while (settingsTemplate->type != 0) {
165		if (settingsTemplate->name != NULL
166			&& !strcmp(name, settingsTemplate->name))
167			return settingsTemplate;
168
169		if (settingsTemplate->name == NULL)
170			wildcardTemplate = settingsTemplate;
171		settingsTemplate++;
172	}
173
174	return wildcardTemplate;
175}
176
177
178const settings_template*
179DriverSettingsMessageAdapter::_FindParentValueTemplate(
180	const settings_template* settingsTemplate)
181{
182	settingsTemplate = settingsTemplate->sub_template;
183	if (settingsTemplate == NULL)
184		return NULL;
185
186	while (settingsTemplate->type != 0) {
187		if (settingsTemplate->parent_value)
188			return settingsTemplate;
189
190		settingsTemplate++;
191	}
192
193	return NULL;
194}
195
196
197status_t
198DriverSettingsMessageAdapter::_AddParameter(const driver_parameter& parameter,
199	const settings_template& settingsTemplate, BMessage& message)
200{
201	const char* name = settingsTemplate.name;
202	if (name == NULL)
203		name = parameter.name;
204
205	for (int32 i = 0; i < parameter.value_count; i++) {
206		if (settingsTemplate.converter != NULL) {
207			status_t status
208				= settingsTemplate.converter->ConvertFromDriverSettings(
209					parameter, name, i, settingsTemplate.type, message);
210			if (status == B_OK)
211				continue;
212			if (status != B_NOT_SUPPORTED)
213				return status;
214		}
215
216		status_t status = B_OK;
217
218		switch (settingsTemplate.type) {
219			case B_STRING_TYPE:
220				status = message.AddString(name, parameter.values[i]);
221				break;
222			case B_INT32_TYPE:
223				status = message.AddInt32(name, atoi(parameter.values[i]));
224				break;
225			case B_BOOL_TYPE:
226			{
227				bool value=!strcasecmp(parameter.values[i], "true")
228					|| !strcasecmp(parameter.values[i], "on")
229					|| !strcasecmp(parameter.values[i], "yes")
230					|| !strcasecmp(parameter.values[i], "enabled")
231					|| !strcasecmp(parameter.values[i], "1");
232				status = message.AddBool(name, value);
233				break;
234			}
235			case B_MESSAGE_TYPE:
236				// Is handled outside of this method
237				break;
238
239			default:
240				return B_BAD_VALUE;
241		}
242		if (status != B_OK)
243			return status;
244	}
245
246	if (parameter.value_count == 0) {
247		if (settingsTemplate.converter != NULL) {
248			status_t status
249				= settingsTemplate.converter->ConvertEmptyFromDriverSettings(
250					parameter, name, settingsTemplate.type, message);
251			if (status == B_NOT_SUPPORTED)
252				return B_OK;
253		} else if (settingsTemplate.type == B_BOOL_TYPE) {
254			// Empty boolean parameters are always true
255			return message.AddBool(name, true);
256		}
257	}
258
259	return B_OK;
260}
261
262
263status_t
264DriverSettingsMessageAdapter::_ConvertFromDriverParameter(
265	const driver_parameter& parameter,
266	const settings_template* settingsTemplate, BMessage& message)
267{
268	settingsTemplate = _FindSettingsTemplate(settingsTemplate, parameter.name);
269	if (settingsTemplate == NULL) {
270		// We almost silently ignore this kind of issues
271		fprintf(stderr, "unknown parameter %s\n", parameter.name);
272		return B_OK;
273	}
274
275	status_t status = _AddParameter(parameter, *settingsTemplate, message);
276	if (status != B_OK)
277		return status;
278
279	if (settingsTemplate->type == B_MESSAGE_TYPE) {
280		BMessage subMessage;
281		for (int32 j = 0; j < parameter.parameter_count; j++) {
282			status = _ConvertFromDriverParameter(parameter.parameters[j],
283				settingsTemplate->sub_template, subMessage);
284			if (status != B_OK)
285				return status;
286		}
287
288		const settings_template* parentValueTemplate
289			= _FindParentValueTemplate(settingsTemplate);
290		if (parentValueTemplate != NULL)
291			status = _AddParameter(parameter, *parentValueTemplate, subMessage);
292		if (status == B_OK)
293			status = message.AddMessage(parameter.name, &subMessage);
294	}
295
296	return status;
297}
298
299
300status_t
301DriverSettingsMessageAdapter::_AppendSettings(
302	const settings_template* settingsTemplate, BString& settings,
303	const BMessage& message, const char* name, type_code type, int32 count,
304	const char* settingName)
305{
306	const settings_template* valueTemplate
307		= _FindSettingsTemplate(settingsTemplate, name);
308	if (valueTemplate == NULL) {
309		fprintf(stderr, "unknown field %s\n", name);
310		return B_BAD_VALUE;
311	}
312
313	if (valueTemplate->type != type) {
314		fprintf(stderr, "field type mismatch %s\n", name);
315		return B_BAD_VALUE;
316	}
317
318	if (settingName == NULL)
319		settingName = name;
320
321	if (type != B_MESSAGE_TYPE) {
322		settings.Append("\n");
323		settings.Append(settingName);
324		settings.Append("\t");
325	}
326
327	for (int32 valueIndex = 0; valueIndex < count; valueIndex++) {
328		if (valueIndex > 0 && type != B_MESSAGE_TYPE)
329			settings.Append(" ");
330
331		if (valueTemplate->converter != NULL) {
332			status_t status = valueTemplate->converter->ConvertToDriverSettings(
333				message, name, type, valueIndex, settings);
334			if (status == B_OK)
335				continue;
336			if (status != B_NOT_SUPPORTED)
337				return status;
338		}
339
340		switch (type) {
341			case B_BOOL_TYPE:
342			{
343				bool value;
344				status_t result = message.FindBool(name, valueIndex, &value);
345				if (result != B_OK)
346					return result;
347
348				settings.Append(value ? "true" : "false");
349				break;
350			}
351
352			case B_STRING_TYPE:
353			{
354				const char* value = NULL;
355				status_t result = message.FindString(name, valueIndex, &value);
356				if (result != B_OK)
357					return result;
358
359				settings.Append(value);
360				break;
361			}
362
363			case B_INT32_TYPE:
364			{
365				int32 value;
366				status_t result = message.FindInt32(name, valueIndex, &value);
367				if (result != B_OK)
368					return result;
369
370				char buffer[100];
371				snprintf(buffer, sizeof(buffer), "%" B_PRId32, value);
372				settings.Append(buffer, sizeof(buffer));
373				break;
374			}
375
376			case B_MESSAGE_TYPE:
377			{
378				BMessage subMessage;
379				status_t result = message.FindMessage(name, valueIndex,
380					&subMessage);
381				if (result != B_OK)
382					return result;
383
384				const settings_template* parentValueTemplate
385					= _FindParentValueTemplate(valueTemplate);
386				if (parentValueTemplate != NULL) {
387					_AppendSettings(valueTemplate->sub_template, settings,
388						subMessage, parentValueTemplate->name,
389						parentValueTemplate->type, 1, name);
390					subMessage.RemoveName(parentValueTemplate->name);
391				}
392
393				BString subSettings;
394				ConvertToDriverSettings(valueTemplate->sub_template,
395					subSettings, subMessage);
396				subSettings.ReplaceAll("\n", "\n\t");
397				subSettings.RemoveFirst("\n");
398
399				if (!subSettings.IsEmpty()) {
400					settings.Append(" {\n");
401					settings.Append(subSettings);
402					settings.Append("\n}");
403				}
404			}
405		}
406	}
407
408	return B_OK;
409}
410