@@ -73,6 +73,13 @@ static std::set<const libcamera::ControlId *> ignored_controls =
7373
7474static auto control_type_values = control_enum_values<libcamera::ControlType>(" ControlType" );
7575
76+ #if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR < 4
77+ // Not supported before 0.4.0
78+ #define CONTROL_ID_IS_ARRAY (ctrl ) (false )
79+ #else
80+ #define CONTROL_ID_IS_ARRAY (ctrl ) (ctrl)->isArray ()
81+ #endif
82+
7683static const std::map<unsigned , std::string> *libcamera_find_control_ids (unsigned control_id)
7784{
7885 auto iter = libcamera_control_ids.find (control_id);
@@ -82,17 +89,20 @@ static const std::map<unsigned, std::string> *libcamera_find_control_ids(unsigne
8289 return &iter->second .enum_values ;
8390}
8491
85- static long long libcamera_find_control_id_named_value (unsigned control_id, const char *name )
92+ static std::pair< long long , const char *> libcamera_find_control_id_named_value (unsigned control_id, const char *value )
8693{
8794 auto named_values = libcamera_find_control_ids (control_id);
8895 if (named_values) {
8996 for (const auto & named_value : *named_values) {
90- if (device_option_is_equal (named_value.second .c_str (), name))
91- return named_value.first ;
97+ if (device_option_is_equal (named_value.second .c_str (), value)) {
98+ return std::make_pair (named_value.first , value + named_value.second .length ());
99+ }
92100 }
93101 }
94102
95- return strtoll (name, NULL , 10 );
103+ char *endptr = NULL ;
104+ auto res = strtoll (value, &endptr, 10 );
105+ return std::make_pair (res, endptr);
96106}
97107
98108static libcamera::ControlInfoMap::Map libcamera_control_list (device_t *dev)
@@ -140,9 +150,10 @@ void libcamera_device_dump_options(device_t *dev, FILE *stream)
140150 auto control_key = libcamera_device_option_normalize (control_id->name ());
141151 auto control_info = control.second ;
142152
143- fprintf (stream, " - available option: %s (%08x, type=%s): %s\n " ,
153+ fprintf (stream, " - available option: %s (%08x, type=%s%s ): %s\n " ,
144154 control_id->name ().c_str (), control_id->id (),
145155 control_type_values[control_id->type ()].c_str (),
156+ CONTROL_ID_IS_ARRAY (control_id) ? " Array" : " " ,
146157 control_info.toString ().c_str ());
147158
148159 auto named_values = libcamera_find_control_ids (control_id->id ());
@@ -321,101 +332,105 @@ int libcamera_device_dump_options2(device_t *dev, device_option_fn fn, void *opa
321332 return n;
322333}
323334
324- static libcamera::Rectangle libcamera_parse_rectangle (const char *value)
335+ static std::pair<float , const char *> libcamera_parse_float (const char *value)
336+ {
337+ char *endptr = NULL ;
338+ auto res = strtof (value, &endptr);
339+ return std::make_pair (res, endptr);
340+ }
341+
342+ static std::pair<libcamera::Rectangle, const char *> libcamera_parse_rectangle (const char *value)
325343{
326344 static const char *RECTANGLE_PATTERNS[] =
327345 {
328- " (%d,%d)/%ux%u" ,
329- " %d,%d,%u,%u" ,
346+ " (%d,%d)/%ux%u%n " ,
347+ " %d,%d,%u,%u%n " ,
330348 NULL
331349 };
332350
333351 for (int i = 0 ; RECTANGLE_PATTERNS[i]; i++) {
334352 libcamera::Rectangle rectangle;
353+ int read = 0 ;
335354
336355 if (4 == sscanf (value, RECTANGLE_PATTERNS[i],
337356 &rectangle.x , &rectangle.y ,
338- &rectangle.width , &rectangle.height )) {
339- return rectangle;
357+ &rectangle.width , &rectangle.height , &read )) {
358+ return std::make_pair ( rectangle, value + read) ;
340359 }
341360 }
342361
343- return libcamera::Rectangle ();
362+ return std::make_pair ( libcamera::Rectangle (), ( const char *) NULL );
344363}
345364
346- static libcamera::Size libcamera_parse_size (const char *value)
365+ static std::pair< libcamera::Size, const char *> libcamera_parse_size (const char *value)
347366{
348367 static const char *SIZE_PATTERNS[] =
349368 {
350- " %ux%u" ,
351- " %u,%u" ,
369+ " %ux%u%n " ,
370+ " %u,%u%n " ,
352371 NULL
353372 };
354373
355374 for (int i = 0 ; SIZE_PATTERNS[i]; i++) {
356375 libcamera::Size size;
376+ int read = 0 ;
357377
358- if (2 == sscanf (value, SIZE_PATTERNS[i], &size.width , &size.height )) {
359- return size;
378+ if (2 == sscanf (value, SIZE_PATTERNS[i], &size.width , &size.height , &read )) {
379+ return std::make_pair ( size, value + read) ;
360380 }
361381 }
362382
363- return libcamera::Size ();
383+ return std::make_pair ( libcamera::Size (), ( const char *) NULL );
364384}
365385
366386#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
367387static libcamera::Point libcamera_parse_point (const char *value)
368388{
369389 static const char *POINT_PATTERNS[] =
370390 {
371- " (%d,%d)" ,
372- " %d,%d" ,
391+ " (%d,%d)%n " ,
392+ " %d,%d%n " ,
373393 NULL
374394 };
375395
376396 for (int i = 0 ; POINT_PATTERNS[i]; i++) {
377397 libcamera::Point point;
398+ int read = 0 ;
378399
379400 if (2 == sscanf (value, POINT_PATTERNS[i],
380- &point.x , &point.y )) {
381- return point;
401+ &point.x , &point.y , &read )) {
402+ return std::make_pair ( point, value + read) ;
382403 }
383404 }
384405
385- return libcamera::Point ();
406+ return std::make_pair ( libcamera::Point (), NULL );
386407}
387408#endif
388409
389410template <typename T, typename F>
390- static bool libcamera_parse_control_value (libcamera::ControlValue &control_value, const char *value, const F & fn)
411+ static bool libcamera_parse_control_value (libcamera::ControlValue &control_value, bool control_array, const char *value, const F& fn)
391412{
392- std::vector<T> parsed ;
413+ std::vector<T> items ;
393414
394415 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 ()));
416+ auto [item, next] = fn (value);
417+ if (!next)
418+ return false ; // failed to parse
419+ items.push_back (item);
420+
421+ if (!*next)
422+ break ; // reached end of elements
423+ if (*next != ' ,' )
424+ return false ; // expected comma to split items
425+ value = ++next;
409426 }
410427
411- if (parsed .empty ()) {
428+ if (items .empty ()) {
412429 return false ;
413- }
414-
415- if (parsed.size () > 1 ) {
416- control_value.set <libcamera::Span<T> >(parsed);
430+ } else if (control_array) {
431+ control_value.set <libcamera::Span<T> >(items);
417432 } else {
418- control_value.set <T>(parsed [0 ]);
433+ control_value.set <T>(items [0 ]);
419434 }
420435
421436 return true ;
@@ -433,42 +448,46 @@ int libcamera_device_set_option(device_t *dev, const char *keyp, const char *val
433448 continue ;
434449
435450 libcamera::ControlValue control_value;
451+ bool control_array = CONTROL_ID_IS_ARRAY (control_id);
436452
437453 switch (control_id->type ()) {
438454 case libcamera::ControlTypeNone:
439455 break ;
440456
441457 case libcamera::ControlTypeBool:
458+ if (control_array) {
459+ throw std::runtime_error (" Array ControlType for boolean is not supported" );
460+ }
442461 control_value.set <bool >(atoi (value));
443462 break ;
444463
445464 case libcamera::ControlTypeByte:
446- libcamera_parse_control_value<unsigned char >(control_value, value,
465+ libcamera_parse_control_value<unsigned char >(control_value, control_array, value,
447466 [control_id](const char *value) { return libcamera_find_control_id_named_value (control_id->id (), value); });
448467 break ;
449468
450469 case libcamera::ControlTypeInteger32:
451- libcamera_parse_control_value<int32_t >(control_value, value,
470+ libcamera_parse_control_value<int32_t >(control_value, control_array, value,
452471 [control_id](const char *value) { return libcamera_find_control_id_named_value (control_id->id (), value); });
453472 break ;
454473
455474 case libcamera::ControlTypeInteger64:
456- libcamera_parse_control_value<int64_t >(control_value, value,
475+ libcamera_parse_control_value<int64_t >(control_value, control_array, value,
457476 [control_id](const char *value) { return libcamera_find_control_id_named_value (control_id->id (), value); });
458477 break ;
459478
460479 case libcamera::ControlTypeFloat:
461- libcamera_parse_control_value<float >(control_value, value, atof );
480+ libcamera_parse_control_value<float >(control_value, control_array, value, libcamera_parse_float );
462481 break ;
463482
464483 case libcamera::ControlTypeRectangle:
465484 libcamera_parse_control_value<libcamera::Rectangle>(
466- control_value, value, libcamera_parse_rectangle);
485+ control_value, control_array, value, libcamera_parse_rectangle);
467486 break ;
468487
469488 case libcamera::ControlTypeSize:
470489 libcamera_parse_control_value<libcamera::Size>(
471- control_value, value, libcamera_parse_size);
490+ control_value, control_array, value, libcamera_parse_size);
472491 break ;
473492
474493 case libcamera::ControlTypeString:
@@ -477,7 +496,7 @@ int libcamera_device_set_option(device_t *dev, const char *keyp, const char *val
477496#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
478497 case libcamera::ControlTypePoint:
479498 libcamera_parse_control_value<libcamera::Point>(
480- control_value, value, libcamera_parse_point);
499+ control_value, control_array, value, libcamera_parse_point);
481500 break ;
482501#endif
483502
0 commit comments