/*
* Copyright 2008-2010 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.liftweb {
package util {
import _root_.scala.collection.mutable._
import _root_.scala.util.parsing.combinator._
/**
* Parser a VCard entry such as
*
* BEGIN:VCARD
* VERSION:2.1
* N:Gump;Forrest
* FN:Forrest Gump
* ORG:Bubba Gump Shrimp Co.
* TITLE:Shrimp Man
* TEL;WORK;VOICE:(111) 555-1212
* TEL;HOME;VOICE:(404) 555-1212
* ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
* END:VCARD
*
*/
object VCardParser extends Parsers {
type Elem = Char
implicit def strToInput(in: String): Input = new _root_.scala.util.parsing.input.CharArrayReader(in.toCharArray)
case class VCardKey(name: String, props: List[(String, String)])
case class VCardEntry(key: VCardKey, value: List[String])
lazy val multiLineSep = opt(elem('\n') ~ elem(' '))
lazy val value = (multiLineSep ~> elem("value", {c => !c.isControl && c != ';'}) <~ multiLineSep).* ^^ {case l => l.mkString}
lazy val spaces = (elem(' ') | elem('\t') | elem('\n') | elem('\r'))*
lazy val key = elem("key", {c => c.isLetterOrDigit || c == '-' || c == '_'}).+ ^^ {case list => list.mkString}
lazy val props = ((((elem(';') ~> key <~ elem('=')) ~ key) ^^ {case a ~ b => (a, b)}) | ((elem(';') ~> key) ^^ {case a => (a, "")}))*
lazy val left = (key ~ props) ^^ {case k ~ l => VCardKey(k, l)}
lazy val expr = (((spaces ~> left ~! elem(':')) ~ repsep(value, ';')) ^^ {case a ~ _ ~ b => VCardEntry(a, b)})+
def parse(in: String): Either[List[VCardEntry], String] = expr(in) match {
case Success(v, r) => Left(v)
case err @ _ => Right(err toString)
}
}
}
}