76
76
static pthread_t mainThread_ ;
77
77
static char * jackErr_ = NULL ;
78
78
static const char * clientName_ = "PortAudio" ;
79
+ static const char * port_regex_suffix = ":.*" ;
79
80
80
81
#define STRINGIZE_HELPER (expr ) #expr
81
82
#define STRINGIZE (expr ) STRINGIZE_HELPER(expr)
@@ -451,6 +452,38 @@ BlockingWaitEmpty( PaStream *s )
451
452
452
453
/* ---- jack driver ---- */
453
454
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
+
454
487
/* BuildDeviceList():
455
488
*
456
489
* The process of determining a list of PortAudio "devices" from
@@ -472,7 +505,12 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
472
505
473
506
const char * * jack_ports = NULL ;
474
507
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 );
476
514
int port_index , client_index , i ;
477
515
double globalSampleRate ;
478
516
regex_t port_regex ;
@@ -490,7 +528,9 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
490
528
* associated with the previous list */
491
529
PaUtil_FreeAllAllocations ( jackApi -> deviceInfoMemory );
492
530
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 );
494
534
tmp_client_name = PaUtil_GroupAllocateMemory ( jackApi -> deviceInfoMemory , jack_client_name_size () );
495
535
496
536
/* We can only retrieve the list of clients indirectly, by first
@@ -512,6 +552,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
512
552
int client_seen = FALSE;
513
553
regmatch_t match_info ;
514
554
const char * port = jack_ports [port_index ];
555
+ PA_DEBUG (( "JACK port found: %s\n" , port ));
515
556
516
557
/* extract the client name from the port name, using a regex
517
558
* that parses the clientname:portname syntax */
@@ -584,11 +625,14 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
584
625
585
626
/* To determine how many input and output channels are available,
586
627
* 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 );
589
633
590
634
/* ... 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 ,
592
636
JACK_PORT_TYPE_FILTER , JackPortIsOutput );
593
637
curDevInfo -> maxInputChannels = 0 ;
594
638
curDevInfo -> defaultLowInputLatency = 0. ;
@@ -609,7 +653,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
609
653
}
610
654
611
655
/* ... 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 ,
613
657
JACK_PORT_TYPE_FILTER , JackPortIsInput );
614
658
curDevInfo -> maxOutputChannels = 0 ;
615
659
curDevInfo -> defaultLowOutputLatency = 0. ;
@@ -629,6 +673,11 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
629
673
free (clientPorts );
630
674
}
631
675
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
+
632
681
/* Add this client to the list of devices */
633
682
commonApi -> deviceInfos [client_index ] = curDevInfo ;
634
683
++ commonApi -> info .deviceCount ;
@@ -1080,8 +1129,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
1080
1129
PaJackHostApiRepresentation * jackHostApi = (PaJackHostApiRepresentation * )hostApi ;
1081
1130
PaJackStream * stream = NULL ;
1082
1131
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 );
1085
1139
const char * * jack_ports = NULL ;
1086
1140
/* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */
1087
1141
int i ;
@@ -1239,7 +1293,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
1239
1293
int err = 0 ;
1240
1294
1241
1295
/* 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 );
1243
1301
UNLESS ( jack_ports = jack_get_ports ( jackHostApi -> jack_client , regex_pattern ,
1244
1302
JACK_PORT_TYPE_FILTER , JackPortIsOutput ), paUnanticipatedHostError );
1245
1303
for ( i = 0 ; i < inputChannelCount && jack_ports [i ]; i ++ )
@@ -1263,7 +1321,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
1263
1321
int err = 0 ;
1264
1322
1265
1323
/* 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 );
1267
1329
UNLESS ( jack_ports = jack_get_ports ( jackHostApi -> jack_client , regex_pattern ,
1268
1330
JACK_PORT_TYPE_FILTER , JackPortIsInput ), paUnanticipatedHostError );
1269
1331
for ( i = 0 ; i < outputChannelCount && jack_ports [i ]; i ++ )
@@ -1769,3 +1831,4 @@ PaError PaJack_GetClientName(const char** clientName)
1769
1831
error :
1770
1832
return result ;
1771
1833
}
1834
+
0 commit comments