@@ -34,14 +34,17 @@ import (
34
34
"arduino.cc/builder/gohasissues"
35
35
"arduino.cc/builder/i18n"
36
36
"arduino.cc/builder/types"
37
+ "bytes"
37
38
"crypto/md5"
38
39
"encoding/hex"
40
+ "errors"
39
41
"io/ioutil"
40
42
"os"
41
43
"os/exec"
42
44
"path/filepath"
43
45
"runtime"
44
46
"strings"
47
+ "unicode/utf8"
45
48
)
46
49
47
50
func KeysOfMapOfStringInterface (input map [string ]interface {}) []string {
@@ -435,30 +438,105 @@ func ParseCppString(line string) (string, string, bool) {
435
438
return "" , line , false
436
439
}
437
440
441
+ s , rem , err := consumeQuotedString (line )
442
+
443
+ return s , rem , err == nil
444
+ }
445
+
446
+ // from package net/mail/message.go
447
+ // consumeQuotedString parses the quoted string at the start of p.
448
+ func consumeQuotedString (s string ) (qs string , rem string , err error ) {
449
+ // Assume first byte is '"'.
438
450
i := 1
439
- res := ""
451
+ qsb := make ([]rune , 0 , 10 )
452
+
453
+ escaped := false
454
+
455
+ Loop:
440
456
for {
441
- if i >= len (line ) {
442
- return "" , line , false
443
- }
457
+ r , size := utf8 .DecodeRuneInString (s [i :])
458
+
459
+ switch {
460
+ case size == 0 :
461
+ return "" , s , errors .New ("Unclosed quoted-string" )
444
462
445
- switch line [i ] {
446
- // Backslash, next character is used unmodified
447
- case '\\' :
448
- i ++
449
- if i >= len (line ) {
450
- return "" , line , false
463
+ case size == 1 && r == utf8 .RuneError :
464
+ return "" , s , errors .New ("Invalid utf-8 in quoted-string" )
465
+
466
+ case escaped :
467
+ // quoted-pair = ("\" (VCHAR / WSP))
468
+
469
+ if ! isVchar (r ) && ! isWSP (r ) {
470
+ return "" , s , errors .New ("Bad character in quoted-string" )
451
471
}
452
- res += string (line [i ])
453
- break
454
- // Quote, end of string
455
- case '"' :
456
- return res , line [i + 1 :], true
472
+
473
+ qsb = append (qsb , r )
474
+ escaped = false
475
+
476
+ case isQtext (r ) || isWSP (r ):
477
+ // qtext (printable US-ASCII excluding " and \), or
478
+ // FWS (almost; we're ignoring CRLF)
479
+ qsb = append (qsb , r )
480
+
481
+ case r == '"' :
482
+ break Loop
483
+
484
+ case r == '\\' :
485
+ escaped = true
486
+
457
487
default :
458
- res += string ( line [ i ] )
459
- break
488
+ return "" , s , errors . New ( "Bad character in quoted-string" )
489
+
460
490
}
461
491
462
- i ++
492
+ i += size
493
+ }
494
+ s = s [i + 1 :]
495
+ if len (qsb ) == 0 {
496
+ return "" , s , errors .New ("Empty quoted-string" )
497
+ }
498
+ return string (qsb ), s , nil
499
+ }
500
+
501
+ // isQtext reports whether r is an RFC 5322 qtext character.
502
+ func isQtext (r rune ) bool {
503
+ // Printable US-ASCII, excluding backslash or quote.
504
+ if r == '\\' || r == '"' {
505
+ return false
506
+ }
507
+ return isVchar (r )
508
+ }
509
+
510
+ // quoteString renders a string as an RFC 5322 quoted-string.
511
+ func quoteString (s string ) string {
512
+ var buf bytes.Buffer
513
+ buf .WriteByte ('"' )
514
+ for _ , r := range s {
515
+ if isQtext (r ) || isWSP (r ) {
516
+ buf .WriteRune (r )
517
+ } else if isVchar (r ) {
518
+ buf .WriteByte ('\\' )
519
+ buf .WriteRune (r )
520
+ }
463
521
}
522
+ buf .WriteByte ('"' )
523
+ return buf .String ()
524
+ }
525
+
526
+ // isVchar reports whether r is an RFC 5322 VCHAR character.
527
+ func isVchar (r rune ) bool {
528
+ // Visible (printing) characters.
529
+ return '!' <= r && r <= '~' || isMultibyte (r )
530
+ }
531
+
532
+ // isMultibyte reports whether r is a multi-byte UTF-8 character
533
+ // as supported by RFC 6532
534
+ func isMultibyte (r rune ) bool {
535
+ return r >= utf8 .RuneSelf
536
+ }
537
+
538
+ // isWSP reports whether r is a WSP (white space).
539
+ // WSP is a space or horizontal tab (RFC 5234 Appendix B).
540
+ func isWSP (r rune ) bool {
541
+ return r == ' ' || r == '\t'
464
542
}
0 commit comments