xref: /haiku/src/kits/shared/DriverSettingsMessageAdapter.cpp (revision c4b6278c027f29e1b0954e2f80281f9efd9c4d04)
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 
DriverSettingsConverter()21 DriverSettingsConverter::DriverSettingsConverter()
22 {
23 }
24 
25 
~DriverSettingsConverter()26 DriverSettingsConverter::~DriverSettingsConverter()
27 {
28 }
29 
30 
31 status_t
ConvertFromDriverSettings(const driver_parameter & parameter,const char * name,int32 index,uint32 type,BMessage & target)32 DriverSettingsConverter::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 
40 status_t
ConvertEmptyFromDriverSettings(const driver_parameter & parameter,const char * name,uint32 type,BMessage & target)41 DriverSettingsConverter::ConvertEmptyFromDriverSettings(
42 	const driver_parameter& parameter, const char* name, uint32 type,
43 	BMessage& target)
44 {
45 	return B_NOT_SUPPORTED;
46 }
47 
48 
49 status_t
ConvertToDriverSettings(const BMessage & source,const char * name,int32 index,uint32 type,BString & value)50 DriverSettingsConverter::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 
DriverSettingsMessageAdapter()60 DriverSettingsMessageAdapter::DriverSettingsMessageAdapter()
61 {
62 }
63 
64 
~DriverSettingsMessageAdapter()65 DriverSettingsMessageAdapter::~DriverSettingsMessageAdapter()
66 {
67 }
68 
69 
70 status_t
ConvertFromDriverSettings(const driver_settings & settings,const settings_template * settingsTemplate,BMessage & message)71 DriverSettingsMessageAdapter::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 
92 status_t
ConvertFromDriverSettings(const char * path,const settings_template * settingsTemplate,BMessage & message)93 DriverSettingsMessageAdapter::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 
113 status_t
ConvertToDriverSettings(const settings_template * settingsTemplate,BString & settings,const BMessage & message)114 DriverSettingsMessageAdapter::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 
134 status_t
ConvertToDriverSettings(const char * path,const settings_template * settingsTemplate,const BMessage & message)135 DriverSettingsMessageAdapter::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 
158 const settings_template*
_FindSettingsTemplate(const settings_template * settingsTemplate,const char * name)159 DriverSettingsMessageAdapter::_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 
178 const settings_template*
_FindParentValueTemplate(const settings_template * settingsTemplate)179 DriverSettingsMessageAdapter::_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 
197 status_t
_AddParameter(const driver_parameter & parameter,const settings_template & settingsTemplate,BMessage & message)198 DriverSettingsMessageAdapter::_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 
263 status_t
_ConvertFromDriverParameter(const driver_parameter & parameter,const settings_template * settingsTemplate,BMessage & message)264 DriverSettingsMessageAdapter::_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 
300 status_t
_AppendSettings(const settings_template * settingsTemplate,BString & settings,const BMessage & message,const char * name,type_code type,int32 count,const char * settingName)301 DriverSettingsMessageAdapter::_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