Skip to content

Commit ffeabc9

Browse files
ximinezdangell7
andauthored
refactor: Simplify STParsedJSON with some helper functions (#5591)
- Add code coverage for STParsedJSON edge cases Co-authored-by: Denis Angell <[email protected]>
1 parent 3cbdf81 commit ffeabc9

File tree

3 files changed

+514
-333
lines changed

3 files changed

+514
-333
lines changed

src/libxrpl/protocol/STParsedJSON.cpp

Lines changed: 175 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,175 @@ non_object_in_array(std::string const& item, Json::UInt index)
202202
" is not an object. Arrays may only contain objects.");
203203
}
204204

205+
template <class STResult, class Integer>
206+
static std::optional<detail::STVar>
207+
parseUnsigned(
208+
SField const& field,
209+
std::string const& json_name,
210+
std::string const& fieldName,
211+
SField const* name,
212+
Json::Value const& value,
213+
Json::Value& error)
214+
{
215+
std::optional<detail::STVar> ret;
216+
217+
try
218+
{
219+
if (value.isString())
220+
{
221+
ret = detail::make_stvar<STResult>(
222+
field,
223+
safe_cast<typename STResult::value_type>(
224+
beast::lexicalCastThrow<Integer>(value.asString())));
225+
}
226+
else if (value.isInt())
227+
{
228+
ret = detail::make_stvar<STResult>(
229+
field,
230+
to_unsigned<typename STResult::value_type>(value.asInt()));
231+
}
232+
else if (value.isUInt())
233+
{
234+
ret = detail::make_stvar<STResult>(
235+
field,
236+
to_unsigned<typename STResult::value_type>(value.asUInt()));
237+
}
238+
else
239+
{
240+
error = bad_type(json_name, fieldName);
241+
return ret;
242+
}
243+
}
244+
catch (std::exception const&)
245+
{
246+
error = invalid_data(json_name, fieldName);
247+
return ret;
248+
}
249+
250+
return ret;
251+
}
252+
253+
template <class STResult, class Integer = std::uint16_t>
254+
static std::optional<detail::STVar>
255+
parseUint16(
256+
SField const& field,
257+
std::string const& json_name,
258+
std::string const& fieldName,
259+
SField const* name,
260+
Json::Value const& value,
261+
Json::Value& error)
262+
{
263+
std::optional<detail::STVar> ret;
264+
265+
try
266+
{
267+
if (value.isString())
268+
{
269+
std::string const strValue = value.asString();
270+
271+
if (!strValue.empty() &&
272+
((strValue[0] < '0') || (strValue[0] > '9')))
273+
{
274+
if (field == sfTransactionType)
275+
{
276+
ret = detail::make_stvar<STResult>(
277+
field,
278+
safe_cast<typename STResult::value_type>(
279+
static_cast<Integer>(
280+
TxFormats::getInstance().findTypeByName(
281+
strValue))));
282+
283+
if (*name == sfGeneric)
284+
name = &sfTransaction;
285+
}
286+
else if (field == sfLedgerEntryType)
287+
{
288+
ret = detail::make_stvar<STResult>(
289+
field,
290+
safe_cast<typename STResult::value_type>(
291+
static_cast<Integer>(
292+
LedgerFormats::getInstance().findTypeByName(
293+
strValue))));
294+
295+
if (*name == sfGeneric)
296+
name = &sfLedgerEntry;
297+
}
298+
else
299+
{
300+
error = invalid_data(json_name, fieldName);
301+
return ret;
302+
}
303+
}
304+
}
305+
if (!ret)
306+
return parseUnsigned<STResult, Integer>(
307+
field, json_name, fieldName, name, value, error);
308+
}
309+
catch (std::exception const&)
310+
{
311+
error = invalid_data(json_name, fieldName);
312+
return ret;
313+
}
314+
315+
return ret;
316+
}
317+
318+
template <class STResult, class Integer = std::uint32_t>
319+
static std::optional<detail::STVar>
320+
parseUint32(
321+
SField const& field,
322+
std::string const& json_name,
323+
std::string const& fieldName,
324+
SField const* name,
325+
Json::Value const& value,
326+
Json::Value& error)
327+
{
328+
std::optional<detail::STVar> ret;
329+
330+
try
331+
{
332+
if (value.isString())
333+
{
334+
if (field == sfPermissionValue)
335+
{
336+
std::string const strValue = value.asString();
337+
auto const granularPermission =
338+
Permission::getInstance().getGranularValue(strValue);
339+
if (granularPermission)
340+
{
341+
ret = detail::make_stvar<STResult>(
342+
field, *granularPermission);
343+
}
344+
else
345+
{
346+
auto const& txType =
347+
TxFormats::getInstance().findTypeByName(strValue);
348+
ret = detail::make_stvar<STResult>(
349+
field,
350+
Permission::getInstance().txToPermissionType(txType));
351+
}
352+
}
353+
else
354+
{
355+
ret = detail::make_stvar<STResult>(
356+
field,
357+
safe_cast<typename STResult::value_type>(
358+
beast::lexicalCastThrow<Integer>(value.asString())));
359+
}
360+
}
361+
if (!ret)
362+
return parseUnsigned<STResult, Integer>(
363+
field, json_name, fieldName, name, value, error);
364+
}
365+
catch (std::exception const&)
366+
{
367+
error = invalid_data(json_name, fieldName);
368+
return ret;
369+
}
370+
371+
return ret;
372+
}
373+
205374
// This function is used by parseObject to parse any JSON type that doesn't
206375
// recurse. Everything represented here is a leaf-type.
207376
static std::optional<detail::STVar>
@@ -302,130 +471,18 @@ parseLeaf(
302471
break;
303472

304473
case STI_UINT16:
305-
try
306-
{
307-
if (value.isString())
308-
{
309-
std::string const strValue = value.asString();
310-
311-
if (!strValue.empty() &&
312-
((strValue[0] < '0') || (strValue[0] > '9')))
313-
{
314-
if (field == sfTransactionType)
315-
{
316-
ret = detail::make_stvar<STUInt16>(
317-
field,
318-
static_cast<std::uint16_t>(
319-
TxFormats::getInstance().findTypeByName(
320-
strValue)));
321-
322-
if (*name == sfGeneric)
323-
name = &sfTransaction;
324-
}
325-
else if (field == sfLedgerEntryType)
326-
{
327-
ret = detail::make_stvar<STUInt16>(
328-
field,
329-
static_cast<std::uint16_t>(
330-
LedgerFormats::getInstance().findTypeByName(
331-
strValue)));
332-
333-
if (*name == sfGeneric)
334-
name = &sfLedgerEntry;
335-
}
336-
else
337-
{
338-
error = invalid_data(json_name, fieldName);
339-
return ret;
340-
}
341-
}
342-
else
343-
{
344-
ret = detail::make_stvar<STUInt16>(
345-
field,
346-
beast::lexicalCastThrow<std::uint16_t>(strValue));
347-
}
348-
}
349-
else if (value.isInt())
350-
{
351-
ret = detail::make_stvar<STUInt16>(
352-
field, to_unsigned<std::uint16_t>(value.asInt()));
353-
}
354-
else if (value.isUInt())
355-
{
356-
ret = detail::make_stvar<STUInt16>(
357-
field, to_unsigned<std::uint16_t>(value.asUInt()));
358-
}
359-
else
360-
{
361-
error = bad_type(json_name, fieldName);
362-
return ret;
363-
}
364-
}
365-
catch (std::exception const&)
366-
{
367-
error = invalid_data(json_name, fieldName);
474+
ret = parseUint16<STUInt16>(
475+
field, json_name, fieldName, name, value, error);
476+
if (!ret)
368477
return ret;
369-
}
370478

371479
break;
372480

373481
case STI_UINT32:
374-
try
375-
{
376-
if (value.isString())
377-
{
378-
if (field == sfPermissionValue)
379-
{
380-
std::string const strValue = value.asString();
381-
auto const granularPermission =
382-
Permission::getInstance().getGranularValue(
383-
strValue);
384-
if (granularPermission)
385-
{
386-
ret = detail::make_stvar<STUInt32>(
387-
field, *granularPermission);
388-
}
389-
else
390-
{
391-
auto const& txType =
392-
TxFormats::getInstance().findTypeByName(
393-
strValue);
394-
ret = detail::make_stvar<STUInt32>(
395-
field,
396-
Permission::getInstance().txToPermissionType(
397-
txType));
398-
}
399-
}
400-
else
401-
{
402-
ret = detail::make_stvar<STUInt32>(
403-
field,
404-
beast::lexicalCastThrow<std::uint32_t>(
405-
value.asString()));
406-
}
407-
}
408-
else if (value.isInt())
409-
{
410-
ret = detail::make_stvar<STUInt32>(
411-
field, to_unsigned<std::uint32_t>(value.asInt()));
412-
}
413-
else if (value.isUInt())
414-
{
415-
ret = detail::make_stvar<STUInt32>(
416-
field, safe_cast<std::uint32_t>(value.asUInt()));
417-
}
418-
else
419-
{
420-
error = bad_type(json_name, fieldName);
421-
return ret;
422-
}
423-
}
424-
catch (std::exception const&)
425-
{
426-
error = invalid_data(json_name, fieldName);
482+
ret = parseUint32<STUInt32>(
483+
field, json_name, fieldName, name, value, error);
484+
if (!ret)
427485
return ret;
428-
}
429486

430487
break;
431488

0 commit comments

Comments
 (0)