diff options
author | iximeow <me@iximeow.net> | 2015-03-02 15:34:34 -0800 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2015-03-02 15:34:34 -0800 |
commit | 9827904a6aa6b649665cf78fa56716011fb37e6d (patch) | |
tree | a7d7ef6c08fa92226bee434f5e6d29d179e80c21 /src/external |
initial commit
Diffstat (limited to 'src/external')
-rw-r--r-- | src/external/Base64.scala | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/external/Base64.scala b/src/external/Base64.scala new file mode 100644 index 0000000..692abb8 --- /dev/null +++ b/src/external/Base64.scala @@ -0,0 +1,69 @@ +package io.github.marklister.base64 + +/** + * Base64 encoder + * @author Mark Lister + * (c) Mark Lister 2014 + * + * I, the copyright holder of this work, release this work into the public domain. + * This applies worldwide. In some countries this may not be legally possible; + * if so: I grant anyone the right to use this work for any purpose, without any + * conditions, unless such conditions are required by law. + * + * The repo for this Base64 encoder lives at https://github.com/marklister/base64 + * Please send your issues, suggestions and pull requests there. + * + */ + +object Base64 { + + class B64Scheme(val encodeTable: IndexedSeq[Char]) { + lazy val decodeTable = collection.immutable.TreeMap(encodeTable.zipWithIndex: _*) + } + + lazy val base64 = new B64Scheme(('A' to 'Z') ++ ('a' to 'z') ++ ('0' to '9') ++ Seq('+', '/')) + lazy val base64Url = new B64Scheme(base64.encodeTable.dropRight(2) ++ Seq('-', '_')) + + implicit class Encoder(b: Array[Byte]) { + private[this] val zero = Array(0, 0).map(_.toByte) + lazy val pad = (3 - b.length % 3) % 3 + + def toBase64(implicit scheme: B64Scheme = base64): String = { + def sixBits(x: Array[Byte]): Seq[Int] = { + val a = (x(0) & 0xfc) >> 2 + val b = ((x(0) & 0x3) << 4) + ((x(1) & 0xf0) >> 4) + val c = ((x(1) & 0xf) << 2) + ((x(2) & 0xc0) >> 6) + val d = (x(2)) & 0x3f + Seq(a, b, c, d) + } + ((b ++ zero.take(pad)).grouped(3) + .flatMap(sixBits(_)) + .map(x => scheme.encodeTable(x)) + .toSeq + .dropRight(pad) :+ "=" * pad) + .mkString + } + } + + implicit class Decoder(s: String) { + lazy val cleanS = s.reverse.dropWhile(_ == '=').reverse + lazy val pad = s.length - cleanS.length + + def toByteArray(implicit scheme: B64Scheme = base64): Array[Byte] = { + def threeBytes(s: Seq[Char]): Array[Byte] = { + val r = s.map(scheme.decodeTable(_)).foldLeft(0)((a,b)=>(a << 6) +b) + java.nio.ByteBuffer.allocate(8).putLong(r).array().takeRight(3) + } + if (pad > 2 || s.length % 4 != 0) throw new java.lang.IllegalArgumentException("Invalid Base64 String:" + s) + if (!cleanS.forall(scheme.encodeTable.contains(_))) throw new java.lang.IllegalArgumentException("Invalid Base64 String:" + s) + + (cleanS + "A" * pad) + .grouped(4) + .map(threeBytes(_)) + .flatten + .toArray + .dropRight(pad) + } + } + +} |