Skip to content

Commit 5ebc86f

Browse files
committed
libcamera: parse arrays for options
This does that by trying to parse value, and then advancing pointer. It checks if the string ends or is split by comma.
1 parent be35795 commit 5ebc86f

File tree

1 file changed

+64
-52
lines changed

1 file changed

+64
-52
lines changed

device/libcamera/options.cc

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,19 @@ static const std::map<unsigned, std::string> *libcamera_find_control_ids(unsigne
8282
return &iter->second.enum_values;
8383
}
8484

85-
static long long libcamera_find_control_id_named_value(unsigned control_id, const char *name)
85+
static long long libcamera_find_control_id_named_value(unsigned control_id, const char **value)
8686
{
8787
auto named_values = libcamera_find_control_ids(control_id);
8888
if (named_values) {
8989
for (const auto & named_value : *named_values) {
90-
if (device_option_is_equal(named_value.second.c_str(), name))
90+
if (device_option_is_equal(named_value.second.c_str(), *value)) {
91+
*value += named_value.second.length();
9192
return named_value.first;
93+
}
9294
}
9395
}
9496

95-
return strtoll(name, NULL, 10);
97+
return strtoll(*value, (char**)value, 10);
9698
}
9799

98100
static libcamera::ControlInfoMap::Map libcamera_control_list(device_t *dev)
@@ -140,9 +142,9 @@ void libcamera_device_dump_options(device_t *dev, FILE *stream)
140142
auto control_key = libcamera_device_option_normalize(control_id->name());
141143
auto control_info = control.second;
142144

143-
fprintf(stream, "- available option: %s (%08x, type=%s): %s\n",
145+
fprintf(stream, "- available option: %s (%08x, type=%s%s): %s\n",
144146
control_id->name().c_str(), control_id->id(),
145-
control_type_values[control_id->type()].c_str(),
147+
control_type_values[control_id->type()].c_str(), control_id->isArray() ? " Array" : "",
146148
control_info.toString().c_str());
147149

148150
auto named_values = libcamera_find_control_ids(control_id->id());
@@ -321,101 +323,107 @@ int libcamera_device_dump_options2(device_t *dev, device_option_fn fn, void *opa
321323
return n;
322324
}
323325

324-
static libcamera::Rectangle libcamera_parse_rectangle(const char *value)
326+
static float libcamera_parse_float(const char **value)
327+
{
328+
return strtof(*value, (char**)value);
329+
}
330+
331+
static libcamera::Rectangle libcamera_parse_rectangle(const char **value)
325332
{
326333
static const char *RECTANGLE_PATTERNS[] =
327334
{
328-
"(%d,%d)/%ux%u",
329-
"%d,%d,%u,%u",
335+
"(%d,%d)/%ux%u%n",
336+
"%d,%d,%u,%u%n",
330337
NULL
331338
};
332339

333340
for (int i = 0; RECTANGLE_PATTERNS[i]; i++) {
334341
libcamera::Rectangle rectangle;
342+
int read = 0;
335343

336-
if (4 == sscanf(value, RECTANGLE_PATTERNS[i],
344+
if (4 == sscanf(*value, RECTANGLE_PATTERNS[i],
337345
&rectangle.x, &rectangle.y,
338-
&rectangle.width, &rectangle.height)) {
346+
&rectangle.width, &rectangle.height, &read)) {
347+
*value += read;
339348
return rectangle;
340349
}
341350
}
342351

352+
value = NULL;
343353
return libcamera::Rectangle();
344354
}
345355

346-
static libcamera::Size libcamera_parse_size(const char *value)
356+
static libcamera::Size libcamera_parse_size(const char **value)
347357
{
348358
static const char *SIZE_PATTERNS[] =
349359
{
350-
"%ux%u",
351-
"%u,%u",
360+
"%ux%u%n",
361+
"%u,%u%n",
352362
NULL
353363
};
354364

355365
for (int i = 0; SIZE_PATTERNS[i]; i++) {
356366
libcamera::Size size;
367+
int read = 0;
357368

358-
if (2 == sscanf(value, SIZE_PATTERNS[i], &size.width, &size.height)) {
369+
if (2 == sscanf(*value, SIZE_PATTERNS[i], &size.width, &size.height, &read)) {
370+
*value += read;
359371
return size;
360372
}
361373
}
362374

375+
*value = NULL;
363376
return libcamera::Size();
364377
}
365378

366379
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
367-
static libcamera::Point libcamera_parse_point(const char *value)
380+
static libcamera::Point libcamera_parse_point(const char **value)
368381
{
369382
static const char *POINT_PATTERNS[] =
370383
{
371-
"(%d,%d)",
372-
"%d,%d",
384+
"(%d,%d)%n",
385+
"%d,%d%n",
373386
NULL
374387
};
375388

376389
for (int i = 0; POINT_PATTERNS[i]; i++) {
377390
libcamera::Point point;
391+
int read = 0;
378392

379-
if (2 == sscanf(value, POINT_PATTERNS[i],
380-
&point.x, &point.y)) {
393+
if (2 == sscanf(*value, POINT_PATTERNS[i],
394+
&point.x, &point.y, &read)) {
395+
*value += read;
381396
return point;
382397
}
383398
}
384399

400+
*value = NULL;
385401
return libcamera::Point();
386402
}
387403
#endif
388404

389-
template<typename T, typename F>
390-
static bool libcamera_parse_control_value(libcamera::ControlValue &control_value, const char *value, const F &fn)
405+
template<typename T>
406+
static bool libcamera_parse_control_value(libcamera::ControlValue &control_value, bool control_array, const char *value, const std::function<T(const char**)>& fn)
391407
{
392-
std::vector<T> parsed;
408+
std::vector<T> items;
393409

394410
while (value && *value) {
395-
std::string current_value;
396-
397-
if (const char *next = strchr(value, ',')) {
398-
current_value.assign(value, next);
399-
value = &next[1];
400-
} else {
401-
current_value.assign(value);
402-
value = NULL;
403-
}
404-
405-
if (current_value.empty())
406-
continue;
407-
408-
parsed.push_back(fn(current_value.c_str()));
411+
items.push_back(fn(&value));
412+
if (!value)
413+
return false; // failed to parse
414+
else if (!*value)
415+
break; // reached end of elements
416+
else if (*value != ',')
417+
return false; // expected comma to split items
418+
value++;
409419
}
410420

411-
if (parsed.empty()) {
421+
if (items.empty()) {
412422
return false;
413-
}
414-
415-
if (parsed.size() > 1) {
416-
control_value.set<libcamera::Span<T> >(parsed);
423+
} else if (control_array) {
424+
control_value.set<libcamera::Span<T> >(items);
417425
} else {
418-
control_value.set<T>(parsed[0]);
426+
control_value.set<T>(items[0]);
419427
}
420428

421429
return true;
@@ -433,42 +441,46 @@ int libcamera_device_set_option(device_t *dev, const char *keyp, const char *val
433441
continue;
434442

435443
libcamera::ControlValue control_value;
444+
bool control_array = control_id->isArray();
436445

437446
switch (control_id->type()) {
438447
case libcamera::ControlTypeNone:
439448
break;
440449

441450
case libcamera::ControlTypeBool:
451+
if (control_array) {
452+
throw std::runtime_error("Array ControlType for boolean is not supported");
453+
}
442454
control_value.set<bool>(atoi(value));
443455
break;
444456

445457
case libcamera::ControlTypeByte:
446-
libcamera_parse_control_value<unsigned char>(control_value, value,
447-
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
458+
libcamera_parse_control_value<unsigned char>(control_value, control_array, value,
459+
[control_id](const char **value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
448460
break;
449461

450462
case libcamera::ControlTypeInteger32:
451-
libcamera_parse_control_value<int32_t>(control_value, value,
452-
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
463+
libcamera_parse_control_value<int32_t>(control_value, control_array, value,
464+
[control_id](const char **value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
453465
break;
454466

455467
case libcamera::ControlTypeInteger64:
456-
libcamera_parse_control_value<int64_t>(control_value, value,
457-
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
468+
libcamera_parse_control_value<int64_t>(control_value, control_array, value,
469+
[control_id](const char **value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
458470
break;
459471

460472
case libcamera::ControlTypeFloat:
461-
libcamera_parse_control_value<float>(control_value, value, atof);
473+
libcamera_parse_control_value<float>(control_value, control_array, value, libcamera_parse_float);
462474
break;
463475

464476
case libcamera::ControlTypeRectangle:
465477
libcamera_parse_control_value<libcamera::Rectangle>(
466-
control_value, value, libcamera_parse_rectangle);
478+
control_value, control_array, value, libcamera_parse_rectangle);
467479
break;
468480

469481
case libcamera::ControlTypeSize:
470482
libcamera_parse_control_value<libcamera::Size>(
471-
control_value, value, libcamera_parse_size);
483+
control_value, control_array, value, libcamera_parse_size);
472484
break;
473485

474486
case libcamera::ControlTypeString:
@@ -477,7 +489,7 @@ int libcamera_device_set_option(device_t *dev, const char *keyp, const char *val
477489
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
478490
case libcamera::ControlTypePoint:
479491
libcamera_parse_control_value<libcamera::Point>(
480-
control_value, value, libcamera_parse_point);
492+
control_value, control_array, value, libcamera_parse_point);
481493
break;
482494
#endif
483495

0 commit comments

Comments
 (0)