1/*
2 * Copyright 2015, Rene Gollent, rene@gollent.com.
3 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
6#include "IntegerValueFormatter.h"
7
8#include <new>
9
10#include <ctype.h>
11
12#include "IntegerFormatter.h"
13#include "IntegerValue.h"
14
15
16// #pragma mark - IntegerValueFormatter
17
18
19IntegerValueFormatter::IntegerValueFormatter(Config* config)
20	:
21	ValueFormatter(),
22	fConfig(config)
23{
24	if (fConfig != NULL)
25		fConfig->AcquireReference();
26}
27
28
29IntegerValueFormatter::~IntegerValueFormatter()
30{
31	if (fConfig != NULL)
32		fConfig->ReleaseReference();
33}
34
35
36Settings*
37IntegerValueFormatter::GetSettings() const
38{
39	return fConfig != NULL ? fConfig->GetSettings() : NULL;
40}
41
42
43status_t
44IntegerValueFormatter::FormatValue(Value* _value, BString& _output)
45{
46	IntegerValue* value = dynamic_cast<IntegerValue*>(_value);
47	if (value == NULL)
48		return B_BAD_VALUE;
49
50	// format the value
51	integer_format format = fConfig != NULL
52		? fConfig->IntegerFormat() : INTEGER_FORMAT_DEFAULT;
53	char buffer[32];
54	if (!IntegerFormatter::FormatValue(value->GetValue(), format,  buffer,
55			sizeof(buffer))) {
56		return B_BAD_VALUE;
57	}
58
59	_output.SetTo(buffer);
60
61	return B_OK;
62}
63
64
65bool
66IntegerValueFormatter::SupportsValidation() const
67{
68	return true;
69}
70
71
72bool
73IntegerValueFormatter::ValidateFormattedValue(const BString& input,
74	type_code type) const
75{
76	::Value* value = NULL;
77	return _PerformValidation(input, type, value, false) == B_OK;
78}
79
80
81status_t
82IntegerValueFormatter::GetValueFromFormattedInput(const BString& input,
83	type_code type, Value*& _output) const
84{
85	return _PerformValidation(input, type, _output, true);
86}
87
88
89status_t
90IntegerValueFormatter::_PerformValidation(const BString& input, type_code type,
91	::Value*& _output, bool wantsValue) const
92{
93	integer_format format;
94	if (fConfig != NULL)
95		format = fConfig->IntegerFormat();
96	else {
97		bool isSigned;
98		if (BVariant::TypeIsInteger(type, &isSigned)) {
99			format = isSigned ? INTEGER_FORMAT_SIGNED
100				: INTEGER_FORMAT_UNSIGNED;
101		} else
102			return B_BAD_VALUE;
103	}
104
105	status_t error = B_OK;
106	if (format == INTEGER_FORMAT_UNSIGNED
107		|| format >= INTEGER_FORMAT_HEX_DEFAULT) {
108		error = _ValidateUnsigned(input, type, _output, format, wantsValue);
109	} else
110		error = _ValidateSigned(input, type, _output, wantsValue);
111
112	return error;
113}
114
115
116status_t
117IntegerValueFormatter::_ValidateSigned(const BString& input, type_code type,
118	::Value*& _output, bool wantsValue) const
119{
120	const char* text = input.String();
121	char *parseEnd = NULL;
122	intmax_t parsedValue = strtoimax(text, &parseEnd, 10);
123	if (parseEnd - text < input.Length() && !isspace(*parseEnd))
124		return B_NO_MEMORY;
125
126	BVariant newValue;
127	switch (type) {
128		case B_INT8_TYPE:
129		{
130			if (parsedValue < INT8_MIN || parsedValue > INT8_MAX)
131				return B_BAD_VALUE;
132
133			newValue.SetTo((int8)parsedValue);
134			break;
135		}
136		case B_INT16_TYPE:
137		{
138			if (parsedValue < INT16_MIN || parsedValue > INT16_MAX)
139				return B_BAD_VALUE;
140
141			newValue.SetTo((int16)parsedValue);
142			break;
143		}
144		case B_INT32_TYPE:
145		{
146			if (parsedValue < INT32_MIN || parsedValue > INT32_MAX)
147				return B_BAD_VALUE;
148
149			newValue.SetTo((int32)parsedValue);
150			break;
151		}
152		case B_INT64_TYPE:
153		{
154			newValue.SetTo((int64)parsedValue);
155			break;
156		}
157		default:
158			return B_BAD_VALUE;
159	}
160
161	if (wantsValue) {
162		_output = new(std::nothrow) IntegerValue(newValue);
163		if (_output == NULL)
164			return B_NO_MEMORY;
165	}
166
167	return B_OK;
168}
169
170
171status_t
172IntegerValueFormatter::_ValidateUnsigned(const BString& input, type_code type,
173	::Value*& _output, integer_format format, bool wantsValue) const
174{
175	const char* text = input.String();
176	int32 base = format == INTEGER_FORMAT_UNSIGNED ? 10 : 16;
177
178	char *parseEnd = NULL;
179	uintmax_t parsedValue = strtoumax(text, &parseEnd, base);
180	if (parseEnd - text < input.Length() && !isspace(*parseEnd))
181		return B_BAD_VALUE;
182
183	BVariant newValue;
184	switch (type) {
185		case B_UINT8_TYPE:
186		{
187			if (parsedValue > UINT8_MAX)
188				return B_BAD_VALUE;
189
190			newValue.SetTo((uint8)parsedValue);
191			break;
192		}
193		case B_UINT16_TYPE:
194		{
195			if (parsedValue > UINT16_MAX)
196				return B_BAD_VALUE;
197
198			newValue.SetTo((uint16)parsedValue);
199			break;
200		}
201		case B_UINT32_TYPE:
202		{
203			if (parsedValue > UINT32_MAX)
204				return B_BAD_VALUE;
205
206			newValue.SetTo((uint32)parsedValue);
207			break;
208		}
209		case B_UINT64_TYPE:
210		{
211			newValue.SetTo((uint64)parsedValue);
212			break;
213		}
214		default:
215			return B_BAD_VALUE;
216	}
217
218	if (wantsValue) {
219		_output = new(std::nothrow) IntegerValue(newValue);
220		if (_output == NULL)
221			return B_NO_MEMORY;
222	}
223
224	return B_OK;
225}
226
227
228
229// #pragma mark - Config
230
231
232IntegerValueFormatter::Config::~Config()
233{
234}
235