Go package for working with the vCard 4.0 format
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

decode.go 2.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package vcard
  2. import (
  3. "fmt"
  4. "bufio"
  5. "io"
  6. "strings"
  7. )
  8. type line struct {
  9. Key string
  10. Value string
  11. }
  12. func (l line) String() string {
  13. return fmt.Sprintf("%v:%v", l.Key, l.Value)
  14. }
  15. func (l line) IsBegin() bool {
  16. return l.Key == BeginKey && l.Value == VCard
  17. }
  18. func (l line) IsEnd() bool {
  19. return l.Key == EndKey && l.Value == VCard
  20. }
  21. func splitLine(s string) (*line, error) {
  22. elems := strings.SplitN(s, ":", 2)
  23. if len(elems) < 2 {
  24. return nil, ErrNoColons
  25. }
  26. return &line{Key: elems[0], Value: elems[1]}, nil
  27. }
  28. type vCardLines []line
  29. func (ls vCardLines) String() string {
  30. lineStrings := []string{}
  31. for _, l := range ls {
  32. lineStrings = append(lineStrings, l.String())
  33. }
  34. return strings.Join(lineStrings, "\n")
  35. }
  36. func getvCardLines(scanner *bufio.Scanner) (vCardLines, error) {
  37. lines := vCardLines{}
  38. for scanner.Scan() {
  39. s := scanner.Text()
  40. l, err := splitLine(s)
  41. if err != nil {
  42. return nil, err
  43. }
  44. if l.IsEnd() {
  45. return lines, nil
  46. } else if l.IsBegin() {
  47. return nil, ErrNoMatchingEnd
  48. }
  49. lines = append(lines, *l)
  50. }
  51. return nil, ErrNoMatchingEnd
  52. }
  53. func getvCardLinesSlice(r io.Reader) ([]vCardLines, error) {
  54. linesSlice := []vCardLines{}
  55. scanner := bufio.NewScanner(r)
  56. for scanner.Scan() {
  57. s := scanner.Text()
  58. l, err := splitLine(s)
  59. if err != nil {
  60. return nil, err
  61. }
  62. if l.IsEnd() {
  63. return nil, ErrNoMatchingBegin
  64. } else if l.IsBegin() {
  65. lines, err := getvCardLines(scanner)
  66. if err != nil {
  67. return nil, err
  68. }
  69. linesSlice = append(linesSlice, lines)
  70. }
  71. }
  72. return linesSlice, nil
  73. }
  74. func (vcard vCardLines) ToContact() (*Contact, error) {
  75. contact := Contact{
  76. Telephones: []Telephone{},
  77. }
  78. for _, l := range vcard {
  79. switch l.Key {
  80. case VersionKey:
  81. contact.Version = l.Value
  82. case FullNameKey:
  83. contact.FullName = l.Value
  84. case NameKey:
  85. name, err := nameFromString(l.Value)
  86. if err != nil {
  87. return nil, err
  88. }
  89. contact.Name = *name
  90. case TelephoneKey:
  91. t, err := telephoneFromString(l.Value)
  92. if err != nil {
  93. return nil, err
  94. }
  95. contact.Telephones = append(contact.Telephones, *t)
  96. }
  97. }
  98. return &contact, nil
  99. }
  100. func Decode(r io.Reader) ([]Contact, error) {
  101. contacts := []Contact{}
  102. linesSlice, err := getvCardLinesSlice(r)
  103. if err != nil {
  104. return nil, err
  105. }
  106. for _, vcard := range linesSlice {
  107. contact, err := vcard.ToContact()
  108. if err != nil {
  109. return nil, err
  110. }
  111. contacts = append(contacts, *contact)
  112. }
  113. return contacts, nil
  114. }