1+ using System . Buffers ;
12using System . Globalization ;
23using System . Text ;
34using ValveKeyValue . Abstraction ;
@@ -6,6 +7,8 @@ namespace ValveKeyValue.Serialization.KeyValues3
67{
78 sealed class KV3TextSerializer : IVisitationListener , IDisposable
89 {
10+ static readonly SearchValues < char > CharsToEscape = SearchValues . Create ( "\n \t \\ \" " ) ;
11+
912 public KV3TextSerializer ( Stream stream , KVHeader header = null )
1013 {
1114 ArgumentNullException . ThrowIfNull ( stream ) ;
@@ -379,9 +382,7 @@ void WriteIndentation()
379382
380383 void WriteText ( string text )
381384 {
382- var isMultiline = text . Contains ( '\n ' , StringComparison . Ordinal ) ;
383-
384- if ( isMultiline )
385+ if ( text . Contains ( '\n ' , StringComparison . Ordinal ) )
385386 {
386387 text = text . Replace ( "\r \n " , "\n " , StringComparison . Ordinal ) ;
387388 text = text . Replace ( "\" \" \" " , "\\ \" \" \" " , StringComparison . Ordinal ) ;
@@ -390,6 +391,12 @@ void WriteText(string text)
390391 writer . Write ( text ) ;
391392 writer . Write ( "\n \" \" \" " ) ;
392393 }
394+ else if ( ! text . AsSpan ( ) . ContainsAny ( CharsToEscape ) )
395+ {
396+ writer . Write ( '"' ) ;
397+ writer . Write ( text ) ;
398+ writer . Write ( '"' ) ;
399+ }
393400 else
394401 {
395402 writer . Write ( '"' ) ;
@@ -398,10 +405,6 @@ void WriteText(string text)
398405 {
399406 switch ( @char )
400407 {
401- case '\n ' :
402- writer . Write ( "\\ n" ) ;
403- break ;
404-
405408 case '\t ' :
406409 writer . Write ( "\\ t" ) ;
407410 break ;
@@ -431,66 +434,61 @@ void WriteKey(string key)
431434 return ;
432435 }
433436
434- var escaped = key . Length == 0 ; // Quote empty strings
435- var sb = new StringBuilder ( key . Length + 2 ) ;
436- sb . Append ( '"' ) ;
437-
438- if ( key . Length > 0 && key [ 0 ] >= '0' && key [ 0 ] <= '9' )
437+ if ( key . Length > 0 && ! char . IsAsciiDigit ( key [ 0 ] ) && ! NeedsQuoting ( key ) )
439438 {
440- // Quote when first character is a digit
441- escaped = true ;
439+ writer . Write ( key ) ;
442440 }
443-
444- foreach ( var @char in key )
441+ else
445442 {
446- switch ( @char )
443+ writer . Write ( '"' ) ;
444+
445+ foreach ( var @char in key )
447446 {
448- case '\t ' :
449- escaped = true ;
450- sb . Append ( '\\ ' ) ;
451- sb . Append ( 't' ) ;
452- break ;
453-
454- case '\n ' :
455- escaped = true ;
456- sb . Append ( '\\ ' ) ;
457- sb . Append ( 'n' ) ;
458- break ;
459-
460- case '"' :
461- escaped = true ;
462- sb . Append ( '\\ ' ) ;
463- sb . Append ( '"' ) ;
464- break ;
465-
466- case '\\ ' :
467- escaped = true ;
468- sb . Append ( '\\ ' ) ;
469- sb . Append ( '\\ ' ) ;
470- break ;
471-
472- default :
473- if ( @char != '.' && @char != '_' && ! char . IsAsciiLetterOrDigit ( @char ) )
474- {
475- escaped = true ;
476- }
477-
478- sb . Append ( @char ) ;
479- break ;
447+ switch ( @char )
448+ {
449+ case '\t ' :
450+ writer . Write ( "\\ t" ) ;
451+ break ;
452+
453+ case '\n ' :
454+ writer . Write ( "\\ n" ) ;
455+ break ;
456+
457+ case '\' ' :
458+ writer . Write ( "\\ '" ) ;
459+ break ;
460+
461+ case '"' :
462+ writer . Write ( "\\ \" " ) ;
463+ break ;
464+
465+ case '\\ ' :
466+ writer . Write ( "\\ \\ " ) ;
467+ break ;
468+
469+ default :
470+ writer . Write ( @char ) ;
471+ break ;
472+ }
480473 }
481- }
482474
483- if ( escaped )
484- {
485- sb . Append ( '"' ) ;
486- writer . Write ( sb . ToString ( ) ) ;
475+ writer . Write ( '"' ) ;
487476 }
488- else
477+
478+ writer . Write ( " = " ) ;
479+ }
480+
481+ static bool NeedsQuoting ( string key )
482+ {
483+ foreach ( var c in key )
489484 {
490- writer . Write ( key ) ;
485+ if ( c != '.' && c != '_' && ! char . IsAsciiLetterOrDigit ( c ) )
486+ {
487+ return true ;
488+ }
491489 }
492490
493- writer . Write ( " = " ) ;
491+ return false ;
494492 }
495493
496494 void WriteFlag ( KVFlag kvFlag )
0 commit comments