diff options
Diffstat (limited to 'src/main/scala')
-rw-r--r-- | src/main/scala/spray/json/ProductFormats.scala | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/src/main/scala/spray/json/ProductFormats.scala b/src/main/scala/spray/json/ProductFormats.scala index 9e494ff..b1aac8e 100644 --- a/src/main/scala/spray/json/ProductFormats.scala +++ b/src/main/scala/spray/json/ProductFormats.scala @@ -17,6 +17,7 @@ package spray.json import java.lang.reflect.Modifier +import scala.annotation.tailrec import scala.util.control.NonFatal /** @@ -87,26 +88,50 @@ trait ProductFormats extends ProductFormatsInstances { } object ProductFormats { - private val operators = Map( - "$eq" -> "=", - "$greater" -> ">", - "$less" -> "<", - "$plus" -> "+", - "$minus" -> "-", - "$times" -> "*", - "$div" -> "/", - "$bang" -> "!", - "$at" -> "@", - "$hash" -> "#", - "$percent" -> "%", - "$up" -> "^", - "$amp" -> "&", - "$tilde" -> "~", - "$qmark" -> "?", - "$bar" -> "|") - private def unmangle(name: String) = operators.foldLeft(name) { case (n, (mangled, unmangled)) => - if (n.indexOf(mangled) >= 0) n.replace(mangled, unmangled) else n + private def unmangle(name: String) = { + import java.lang.{StringBuilder => JStringBuilder} + @tailrec def rec(ix: Int, builder: JStringBuilder): String = { + val rem = name.length - ix + if (rem > 0) { + var ch = name.charAt(ix) + var ni = ix + 1 + val sb = if (ch == '$' && rem > 1) { + def c(offset: Int, ch: Char) = name.charAt(ix + offset) == ch + ni = name.charAt(ix + 1) match { + case 'a' if rem > 3 && c(2, 'm') && c(3, 'p') => { ch = '&'; ix + 4 } + case 'a' if rem > 2 && c(2, 't') => { ch = '@'; ix + 3 } + case 'b' if rem > 4 && c(2, 'a') && c(3, 'n') && c(4, 'g') => { ch = '!'; ix + 5 } + case 'b' if rem > 3 && c(2, 'a') && c(3, 'r') => { ch = '|'; ix + 4 } + case 'd' if rem > 3 && c(2, 'i') && c(3, 'v') => { ch = '/'; ix + 4 } + case 'e' if rem > 2 && c(2, 'q') => { ch = '='; ix + 3 } + case 'g' if rem > 7 && c(2, 'r') && c(3, 'e') && c(4, 'a') && c(5, 't') && c(6, 'e') && c(7, 'r') => { ch = '>'; ix + 8 } + case 'h' if rem > 4 && c(2, 'a') && c(3, 's') && c(4, 'h') => { ch = '#'; ix + 5 } + case 'l' if rem > 4 && c(2, 'e') && c(3, 's') && c(4, 's') => { ch = '<'; ix + 5 } + case 'm' if rem > 5 && c(2, 'i') && c(3, 'n') && c(4, 'u') && c(5, 's') => { ch = '-'; ix + 6 } + case 'p' if rem > 7 && c(2, 'e') && c(3, 'r') && c(4, 'c') && c(5, 'e') && c(6, 'n') && c(7, 't') => { ch = '%'; ix + 8 } + case 'p' if rem > 4 && c(2, 'l') && c(3, 'u') && c(4, 's') => { ch = '+'; ix + 5 } + case 'q' if rem > 5 && c(2, 'm') && c(3, 'a') && c(4, 'r') && c(5, 'k') => { ch = '?'; ix + 6 } + case 't' if rem > 5 && c(2, 'i') && c(3, 'l') && c(4, 'd') && c(5, 'e') => { ch = '~'; ix + 6 } + case 't' if rem > 5 && c(2, 'i') && c(3, 'm') && c(4, 'e') && c(5, 's') => { ch = '*'; ix + 6 } + case 'u' if rem > 2 && c(2, 'p') => { ch = '^'; ix + 3 } + case 'u' if rem > 5 => + def hexValue(offset: Int): Int = { + val c = name.charAt(ix + offset) + if ('0' <= c && c <= '9') c - '0' + else if ('a' <= c && c <= 'f') c - 87 + else if ('A' <= c && c <= 'F') c - 55 else -0xFFFF + } + val ci = (hexValue(2) << 12) + (hexValue(3) << 8) + (hexValue(4) << 4) + hexValue(5) + if (ci >= 0) { ch = ci.toChar; ix + 6 } else ni + case _ => ni + } + if (ni > ix + 1 && builder == null) new JStringBuilder(name.substring(0, ix)) else builder + } else builder + rec(ni, if (sb != null) sb.append(ch) else null) + } else if (builder != null) builder.toString else name + } + rec(0, null) } } |