just unfold everything beforehand and use a scanner

This commit is contained in:
gutmet 2022-03-27 12:58:39 +02:00
parent 0e4994ee56
commit 102fc57c2a

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"bufio"
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"io" "io"
@ -11,10 +12,6 @@ import (
"time" "time"
) )
func complain(s string) {
fmt.Fprintln(os.Stderr, s)
}
func optExit(err error) { func optExit(err error) {
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
@ -22,46 +19,8 @@ func optExit(err error) {
} }
} }
// the vCard RFC says, a single logical line can be "folded" to multiple physical lines, func unfold(s string) string {
// so this shit must be done return strings.ReplaceAll(strings.ReplaceAll(s, "\r\n ", ""), "\r\n\t", "")
type UnfoldingReader struct {
buf []byte
i int
j int
}
func NewUnfoldingReader(buf []byte) *UnfoldingReader {
return &UnfoldingReader{buf, 0, 0}
}
func replaceFold(s string) string {
// Yes, I know and I don't care
return strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(s, "\r\n ", ""), "\r\n\t", ""))
}
func (r *UnfoldingReader) ReadLine() (string, bool) {
readCR := false
readCRLF := false
for r.j = r.i; r.j < len(r.buf); r.j++ {
if r.buf[r.j] == '\r' {
readCR = true
} else if readCR && r.buf[r.j] == '\n' {
readCRLF = true
} else if readCRLF && r.buf[r.j] != ' ' && r.buf[r.j] != '\t' {
break
} else {
readCRLF = false
}
}
var s string
if r.i < len(r.buf) {
s = replaceFold(string(r.buf[r.i:r.j]))
} else {
s = ""
}
notEOB := (r.i < len(r.buf))
r.i = r.j
return s, notEOB
} }
func vCardValue(line string) string { func vCardValue(line string) string {
@ -185,9 +144,11 @@ func (n *Number) WriteFritzboxXML(s io.Writer, i int) {
} }
func GetContacts(buf []byte) (c ContactSet) { func GetContacts(buf []byte) (c ContactSet) {
r := NewUnfoldingReader(buf) s := unfold(string(buf))
scanner := bufio.NewScanner(strings.NewReader(s))
var current *Contact var current *Contact
for l, ok := r.ReadLine(); ok; l, ok = r.ReadLine() { for scanner.Scan() {
l := strings.TrimSpace(scanner.Text())
if l == "BEGIN:VCARD" { if l == "BEGIN:VCARD" {
current = &Contact{} current = &Contact{}
} else if l == "END:VCARD" { } else if l == "END:VCARD" {
@ -197,6 +158,7 @@ func GetContacts(buf []byte) (c ContactSet) {
current.setValue(l) current.setValue(l)
} }
} }
optExit(scanner.Err())
if current != nil { if current != nil {
c = append(c, *current) c = append(c, *current)
} }