66// our own file functions allows us to provide transparent support of
77// different line endings, gzip'd print files, PPD files, etc.
88//
9- // Copyright © 2020-2025 by OpenPrinting.
9+ // Copyright © 2020-2026 by OpenPrinting.
1010// Copyright © 2007-2019 by Apple Inc.
1111// Copyright © 1997-2007 by Easy Software Products, all rights reserved.
1212//
@@ -622,8 +622,7 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
622622 // Range check input...
623623 DEBUG_printf ("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT ", value=%p, linenum=%p)" , (void * )fp , (void * )buf , CUPS_LLCAST buflen , (void * )value , (void * )linenum );
624624
625- if (!fp || (fp -> mode != 'r' && fp -> mode != 's' ) ||
626- !buf || buflen < 2 || !value )
625+ if (!fp || (fp -> mode != 'r' && fp -> mode != 's' ) || !buf || buflen < 2 || !value )
627626 {
628627 if (value )
629628 * value = NULL ;
@@ -638,31 +637,33 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
638637 {
639638 (* linenum ) ++ ;
640639
641- // Strip any comments...
642- if (( ptr = strchr ( buf , '#' )) != NULL )
640+ // Handle escaped characters and strip any comments...
641+ for ( ptr = buf ; * ptr ; ptr ++ )
643642 {
644- if (ptr > buf && ptr [ -1 ] == '\\ ' )
643+ if (* ptr == '# ' )
645644 {
646- // Unquote the #...
647- _cups_strcpy (ptr - 1 , ptr );
645+ // Strip comment text...
646+ * ptr = '\0' ;
647+ break ;
648648 }
649- else
649+ else if ( * ptr == '\\' && ( ptr [ 1 ] == '\\' || ptr [ 1 ] == '#' || ptr [ 1 ] == 'n' || ptr [ 1 ] == 'r' ))
650650 {
651- // Strip the comment and any trailing whitespace...
652- while (ptr > buf )
653- {
654- if (!_cups_isspace (ptr [-1 ]))
655- break ;
651+ // \\, \#, \n, or \r, remove backslash and update the escaped char as needed...
652+ _cups_strcpy (ptr , ptr + 1 );
656653
657- ptr -- ;
658- }
659-
660- * ptr = '\0 ' ;
654+ if ( * ptr == 'n' )
655+ * ptr = '\n' ;
656+ else if ( * ptr == 'r' )
657+ * ptr = '\r ' ;
661658 }
662659 }
663660
664661 // Strip leading whitespace...
665- for (ptr = buf ; _cups_isspace (* ptr ); ptr ++ );
662+ for (ptr = buf ; * ptr ; ptr ++ )
663+ {
664+ if (!_cups_isspace (* ptr ))
665+ break ;
666+ }
666667
667668 if (ptr > buf )
668669 _cups_strcpy (buf , ptr );
@@ -672,8 +673,10 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
672673 {
673674 // Yes, grab any value and return...
674675 for (ptr = buf ; * ptr ; ptr ++ )
676+ {
675677 if (_cups_isspace (* ptr ))
676678 break ;
679+ }
677680
678681 if (* ptr )
679682 {
@@ -688,7 +691,9 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
688691 ptr += strlen (ptr ) - 1 ;
689692
690693 if (buf [0 ] == '<' && * ptr == '>' )
694+ {
691695 * ptr -- = '\0' ;
696+ }
692697 else if (buf [0 ] == '<' && * ptr != '>' )
693698 {
694699 // Syntax error...
@@ -1295,7 +1300,7 @@ cupsFilePutChar(cups_file_t *fp, // I - CUPS file
12951300//
12961301// 'cupsFilePutConf()' - Write a configuration line.
12971302//
1298- // This function handles any comment escaping of the value.
1303+ // This function handles any escaping of the value.
12991304//
13001305// @since CUPS 1.4@
13011306//
@@ -1307,7 +1312,6 @@ cupsFilePutConf(cups_file_t *fp, // I - CUPS file
13071312{
13081313 ssize_t bytes , // Number of bytes written
13091314 temp ; // Temporary byte count
1310- const char * ptr ; // Pointer into value
13111315
13121316
13131317 if (!fp || !directive || !* directive )
@@ -1316,31 +1320,66 @@ cupsFilePutConf(cups_file_t *fp, // I - CUPS file
13161320 if ((bytes = cupsFilePuts (fp , directive )) < 0 )
13171321 return (-1 );
13181322
1319- if (cupsFilePutChar (fp , ' ' ) < 0 )
1320- return (-1 );
1321- bytes ++ ;
1322-
13231323 if (value && * value )
13241324 {
1325- if ((ptr = strchr (value , '#' )) != NULL )
1325+ const char * start , // Start of current fragment
1326+ * ptr ; // Pointer into value
1327+
1328+ if (cupsFilePutChar (fp , ' ' ) < 0 )
1329+ return (-1 );
1330+ bytes ++ ;
1331+
1332+ for (start = ptr = value ; * ptr ; ptr ++ )
13261333 {
1327- // Need to quote the first # in the info string...
1328- if ((temp = cupsFileWrite (fp , value , (size_t )(ptr - value ))) < 0 )
1329- return (-1 );
1330- bytes += temp ;
1334+ if (strchr ("#\\\n\r" , * ptr ) != NULL )
1335+ {
1336+ // Character that needs to be escaped...
1337+ if (ptr > start )
1338+ {
1339+ // Write unescaped portion...
1340+ if ((temp = cupsFileWrite (fp , start , (size_t )(ptr - start ))) < 0 )
1341+ return (-1 );
13311342
1332- if (cupsFilePutChar (fp , '\\' ) < 0 )
1333- return (-1 );
1334- bytes ++ ;
1343+ bytes += temp ;
1344+ }
13351345
1336- if ((temp = cupsFilePuts (fp , ptr )) < 0 )
1337- return (-1 );
1338- bytes += temp ;
1346+ start = ptr + 1 ;
1347+
1348+ if (* ptr == '\\' )
1349+ {
1350+ // "\" (for escaping)
1351+ if (cupsFilePuts (fp , "\\\\" ) < 0 )
1352+ return (-1 );
1353+ }
1354+ else if (* ptr == '#' )
1355+ {
1356+ // "#" (for comment)
1357+ if (cupsFilePuts (fp , "\\#" ) < 0 )
1358+ return (-1 );
1359+ }
1360+ else if (* ptr == '\n' )
1361+ {
1362+ // LF
1363+ if (cupsFilePuts (fp , "\\n" ) < 0 )
1364+ return (-1 );
1365+ }
1366+ else if (cupsFilePuts (fp , "\\r" ) < 0 )
1367+ {
1368+ return (-1 );
1369+ }
1370+
1371+ bytes += 2 ;
1372+ }
13391373 }
1340- else if ((temp = cupsFilePuts (fp , value )) < 0 )
1341- return (-1 );
1342- else
1374+
1375+ if (ptr > start )
1376+ {
1377+ // Write remaining unescaped portion...
1378+ if ((temp = cupsFileWrite (fp , start , (size_t )(ptr - start ))) < 0 )
1379+ return (-1 );
1380+
13431381 bytes += temp ;
1382+ }
13441383 }
13451384
13461385 if (cupsFilePutChar (fp , '\n' ) < 0 )
0 commit comments