7676static pthread_t mainThread_ ;
7777static char * jackErr_ = NULL ;
7878static const char * clientName_ = "PortAudio" ;
79+ static const char * port_regex_suffix = ":.*" ;
7980
8081#define STRINGIZE_HELPER (expr ) #expr
8182#define STRINGIZE (expr ) STRINGIZE_HELPER(expr)
@@ -451,6 +452,38 @@ BlockingWaitEmpty( PaStream *s )
451452
452453/* ---- jack driver ---- */
453454
455+ /* copy null terminated string source to destination, escaping regex characters with '\\' in the process */
456+ static void copy_string_and_escape_regex_chars ( char * destination , const char * source , size_t destbuffersize )
457+ {
458+ assert ( destination != source );
459+ assert ( destbuffersize > 0 );
460+
461+ char * dest = destination ;
462+ /* dest_stop is the last location that we can null-terminate the string */
463+ char * dest_stop = destination + (destbuffersize - 1 );
464+
465+ const char * src = source ;
466+
467+ while ( * src != '\0' && dest != dest_stop )
468+ {
469+ const char c = * src ;
470+ if ( strchr ( "\\()[]{}*+?|$^." , c ) != NULL )
471+ {
472+ if ( (dest + 1 ) == dest_stop )
473+ break ; /* only proceed if we can write both c and the escape */
474+
475+ * dest = '\\' ;
476+ dest ++ ;
477+ }
478+ * dest = c ;
479+ dest ++ ;
480+
481+ src ++ ;
482+ }
483+
484+ * dest = '\0' ;
485+ }
486+
454487/* BuildDeviceList():
455488 *
456489 * The process of determining a list of PortAudio "devices" from
@@ -472,7 +505,12 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
472505
473506 const char * * jack_ports = NULL ;
474507 char * * client_names = NULL ;
475- char * regex_pattern = NULL ;
508+ char * port_regex_string = NULL ;
509+ char * device_name_regex_escaped = NULL ;
510+ // In the worst case scenario, every character would be escaped, doubling the string size.
511+ // Add 1 for null terminator.
512+ size_t device_name_regex_escaped_size = jack_client_name_size () * 2 + 1 ;
513+ size_t port_regex_size = device_name_regex_escaped_size + strlen (port_regex_suffix );
476514 int port_index , client_index , i ;
477515 double globalSampleRate ;
478516 regex_t port_regex ;
@@ -490,7 +528,9 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
490528 * associated with the previous list */
491529 PaUtil_FreeAllAllocations ( jackApi -> deviceInfoMemory );
492530
493- regex_pattern = PaUtil_GroupAllocateMemory ( jackApi -> deviceInfoMemory , jack_client_name_size () + 3 );
531+ port_regex_string = PaUtil_GroupAllocateMemory ( jackApi -> deviceInfoMemory , port_regex_size );
532+ device_name_regex_escaped = PaUtil_GroupAllocateMemory (
533+ jackApi -> deviceInfoMemory , device_name_regex_escaped_size );
494534 tmp_client_name = PaUtil_GroupAllocateMemory ( jackApi -> deviceInfoMemory , jack_client_name_size () );
495535
496536 /* We can only retrieve the list of clients indirectly, by first
@@ -512,6 +552,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
512552 int client_seen = FALSE;
513553 regmatch_t match_info ;
514554 const char * port = jack_ports [port_index ];
555+ PA_DEBUG (( "JACK port found: %s\n" , port ));
515556
516557 /* extract the client name from the port name, using a regex
517558 * that parses the clientname:portname syntax */
@@ -584,11 +625,14 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
584625
585626 /* To determine how many input and output channels are available,
586627 * we re-query jackd with more specific parameters. */
587-
588- sprintf ( regex_pattern , "%s:.*" , client_names [client_index ] );
628+ copy_string_and_escape_regex_chars ( device_name_regex_escaped ,
629+ client_names [client_index ],
630+ device_name_regex_escaped_size );
631+ strncpy ( port_regex_string , device_name_regex_escaped , port_regex_size );
632+ strncat ( port_regex_string , port_regex_suffix , port_regex_size );
589633
590634 /* ... what are your output ports (that we could input from)? */
591- clientPorts = jack_get_ports ( jackApi -> jack_client , regex_pattern ,
635+ clientPorts = jack_get_ports ( jackApi -> jack_client , port_regex_string ,
592636 JACK_PORT_TYPE_FILTER , JackPortIsOutput );
593637 curDevInfo -> maxInputChannels = 0 ;
594638 curDevInfo -> defaultLowInputLatency = 0. ;
@@ -609,7 +653,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
609653 }
610654
611655 /* ... what are your input ports (that we could output to)? */
612- clientPorts = jack_get_ports ( jackApi -> jack_client , regex_pattern ,
656+ clientPorts = jack_get_ports ( jackApi -> jack_client , port_regex_string ,
613657 JACK_PORT_TYPE_FILTER , JackPortIsInput );
614658 curDevInfo -> maxOutputChannels = 0 ;
615659 curDevInfo -> defaultLowOutputLatency = 0. ;
@@ -629,6 +673,11 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
629673 free (clientPorts );
630674 }
631675
676+ PA_DEBUG (( "Adding JACK device %s with %d input channels and %d output channels\n" ,
677+ client_names [client_index ],
678+ curDevInfo -> maxInputChannels ,
679+ curDevInfo -> maxOutputChannels ));
680+
632681 /* Add this client to the list of devices */
633682 commonApi -> deviceInfos [client_index ] = curDevInfo ;
634683 ++ commonApi -> info .deviceCount ;
@@ -1080,8 +1129,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
10801129 PaJackHostApiRepresentation * jackHostApi = (PaJackHostApiRepresentation * )hostApi ;
10811130 PaJackStream * stream = NULL ;
10821131 char * port_string = PaUtil_GroupAllocateMemory ( jackHostApi -> deviceInfoMemory , jack_port_name_size () );
1083- unsigned long regexSz = jack_client_name_size () + 3 ;
1084- char * regex_pattern = PaUtil_GroupAllocateMemory ( jackHostApi -> deviceInfoMemory , regexSz );
1132+ // In the worst case every character would be escaped which would double the string length.
1133+ // Add 1 for null terminator
1134+ size_t regex_escaped_client_name_length = jack_client_name_size () * 2 + 1 ;
1135+ char * regex_escaped_client_name = PaUtil_GroupAllocateMemory (
1136+ jackHostApi -> deviceInfoMemory , regex_escaped_client_name_length );
1137+ unsigned long regex_size = jack_client_name_size () * 2 + 1 + strlen (port_regex_suffix );
1138+ char * regex_pattern = PaUtil_GroupAllocateMemory ( jackHostApi -> deviceInfoMemory , regex_size );
10851139 const char * * jack_ports = NULL ;
10861140 /* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */
10871141 int i ;
@@ -1239,7 +1293,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
12391293 int err = 0 ;
12401294
12411295 /* Get output ports of our capture device */
1242- snprintf ( regex_pattern , regexSz , "%s:.*" , hostApi -> deviceInfos [ inputParameters -> device ]-> name );
1296+ copy_string_and_escape_regex_chars ( regex_escaped_client_name ,
1297+ hostApi -> deviceInfos [ inputParameters -> device ]-> name ,
1298+ regex_escaped_client_name_length );
1299+ strncpy ( regex_pattern , regex_escaped_client_name , regex_size );
1300+ strncat ( regex_pattern , port_regex_suffix , regex_size );
12431301 UNLESS ( jack_ports = jack_get_ports ( jackHostApi -> jack_client , regex_pattern ,
12441302 JACK_PORT_TYPE_FILTER , JackPortIsOutput ), paUnanticipatedHostError );
12451303 for ( i = 0 ; i < inputChannelCount && jack_ports [i ]; i ++ )
@@ -1263,7 +1321,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
12631321 int err = 0 ;
12641322
12651323 /* Get input ports of our playback device */
1266- snprintf ( regex_pattern , regexSz , "%s:.*" , hostApi -> deviceInfos [ outputParameters -> device ]-> name );
1324+ copy_string_and_escape_regex_chars ( regex_escaped_client_name ,
1325+ hostApi -> deviceInfos [ outputParameters -> device ]-> name ,
1326+ regex_escaped_client_name_length );
1327+ strncpy ( regex_pattern , regex_escaped_client_name , regex_size );
1328+ strncat ( regex_pattern , port_regex_suffix , regex_size );
12671329 UNLESS ( jack_ports = jack_get_ports ( jackHostApi -> jack_client , regex_pattern ,
12681330 JACK_PORT_TYPE_FILTER , JackPortIsInput ), paUnanticipatedHostError );
12691331 for ( i = 0 ; i < outputChannelCount && jack_ports [i ]; i ++ )
@@ -1769,3 +1831,4 @@ PaError PaJack_GetClientName(const char** clientName)
17691831error :
17701832 return result ;
17711833}
1834+
0 commit comments