106 lines
2.7 KiB
Go
106 lines
2.7 KiB
Go
package ical
|
|
|
|
import (
|
|
"log"
|
|
"errors"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
func ParseCalendar(data string) (*Node, error) {
|
|
r := regexp.MustCompile("([\r|\t| ]*\n[\r|\t| ]*)+")
|
|
lines := r.Split(strings.TrimSpace(data), -1)
|
|
node, _, err, _ := parseCalendarNode(lines, 0)
|
|
|
|
return node, err
|
|
}
|
|
|
|
func parseCalendarNode(lines []string, lineIndex int) (*Node, bool, error, int) {
|
|
line := strings.TrimSpace(lines[lineIndex])
|
|
_ = log.Println
|
|
colonIndex := strings.Index(line, ":")
|
|
if colonIndex <= 0 {
|
|
return nil, false, errors.New("Invalid value/pair: " + line), lineIndex + 1
|
|
}
|
|
name := line[0:colonIndex]
|
|
splitted := strings.Split(name, ";")
|
|
var parameters map[string]string
|
|
if len(splitted) >= 2 {
|
|
name = splitted[0]
|
|
parameters = make(map[string]string)
|
|
for i := 1; i < len(splitted); i++ {
|
|
p := strings.Split(splitted[i], "=")
|
|
if len(p) != 2 { panic("Invalid parameter format: " + name) }
|
|
parameters[p[0]] = p[1]
|
|
}
|
|
}
|
|
value := line[colonIndex+1:len(line)]
|
|
|
|
if name == "BEGIN" {
|
|
node := new(Node)
|
|
node.Name = value
|
|
node.Type = 1
|
|
lineIndex = lineIndex + 1
|
|
for {
|
|
child, finished, _, newLineIndex := parseCalendarNode(lines, lineIndex)
|
|
if finished {
|
|
return node, false, nil, newLineIndex
|
|
} else {
|
|
if child != nil {
|
|
node.Children = append(node.Children, child)
|
|
}
|
|
lineIndex = newLineIndex
|
|
}
|
|
}
|
|
} else if name == "END" {
|
|
return nil, true, nil, lineIndex + 1
|
|
} else {
|
|
node := new(Node)
|
|
node.Name = name
|
|
if name == "DESCRIPTION" || name == "SUMMARY" {
|
|
text, newLineIndex := parseTextType(lines, lineIndex)
|
|
node.Value = text
|
|
node.Parameters = parameters
|
|
return node, false, nil, newLineIndex
|
|
} else {
|
|
node.Value = value
|
|
node.Parameters = parameters
|
|
return node, false, nil, lineIndex + 1
|
|
}
|
|
}
|
|
|
|
panic("Unreachable")
|
|
return nil, false, nil, lineIndex + 1
|
|
}
|
|
|
|
func parseTextType(lines []string, lineIndex int) (string, int) {
|
|
line := lines[lineIndex]
|
|
colonIndex := strings.Index(line, ":")
|
|
output := strings.TrimSpace(line[colonIndex+1:len(line)])
|
|
lineIndex++
|
|
for {
|
|
line := lines[lineIndex]
|
|
if line == "" || line[0] != ' ' {
|
|
return unescapeTextType(output), lineIndex
|
|
}
|
|
output += line[1:len(line)]
|
|
lineIndex++
|
|
}
|
|
return unescapeTextType(output), lineIndex
|
|
}
|
|
|
|
func escapeTextType(input string) string {
|
|
output := strings.Replace(input, "\\", "\\\\", -1)
|
|
output = strings.Replace(output, ";", "\\;", -1)
|
|
output = strings.Replace(output, ",", "\\,", -1)
|
|
output = strings.Replace(output, "\n", "\\n", -1)
|
|
return output
|
|
}
|
|
|
|
func unescapeTextType(s string) string {
|
|
s = strings.Replace(s, "\\;", ";", -1)
|
|
s = strings.Replace(s, "\\,", ",", -1)
|
|
s = strings.Replace(s, "\\n", "\n", -1)
|
|
s = strings.Replace(s, "\\\\", "\\", -1)
|
|
return s
|
|
}
|