-
-
Notifications
You must be signed in to change notification settings - Fork 285
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use an internal Base64 implementation.
Fixes #34
- Loading branch information
Showing
5 changed files
with
109 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
scalapb-runtime/src/main/scala/com/trueaccord/scalapb/Encoding.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package com.trueaccord.scalapb | ||
|
||
import scala.collection.mutable | ||
|
||
/** Utility functions to encode/decode byte arrays as Base64 strings. | ||
* | ||
* Used internally between the protocol buffer compiler and the runtime to encode | ||
* messages. | ||
* | ||
* We could have used Apache Commons, but we would like to avoid an additional dependency. | ||
* javax.xm.bind.DayaTypeConverter.parseBase64Binary is not available on Android. And the Java | ||
* native java.util.Base64 is only available for Java 8... | ||
*/ | ||
object Encoding { | ||
private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" | ||
|
||
def fromBase64(textInput: String): Array[Byte] = { | ||
fromBase64Inner(textInput.filter(alphabet.contains(_: Char))) | ||
} | ||
|
||
private def fromBase64Inner(input: String): Array[Byte] = { | ||
require(input.length % 4 == 0) | ||
val lastEqualsIndex = input.indexOf('=') | ||
val outputLength = (input.length * 3) / 4 - ( | ||
if (lastEqualsIndex > 0) (input.length() - input.indexOf('=')) else 0) | ||
val builder = mutable.ArrayBuilder.make[Byte] | ||
builder.sizeHint(outputLength) | ||
|
||
for { i <- 0 until(input.length, 4) } { | ||
val b = input.substring(i, i + 4).map(alphabet.indexOf(_: Char).toByte) | ||
builder += ((b(0) << 2) | (b(1) >> 4)).toByte | ||
if (b(2) < 64) { | ||
builder += ((b(1) << 4) | (b(2) >> 2)).toByte | ||
if (b(3) < 64) { | ||
builder += ((b(2) << 6) | b(3)).toByte | ||
} | ||
} | ||
} | ||
builder.result() | ||
} | ||
|
||
def toBase64(in: Array[Byte]): String = { | ||
val out = mutable.StringBuilder.newBuilder | ||
var b: Int = 0 | ||
for { i <- 0 until (in.length, 3) } { | ||
b = (in(i) & 0xFC) >> 2 | ||
out.append(alphabet(b)) | ||
b = (in(i) & 0x03) << 4 | ||
if (i + 1 < in.length) { | ||
b |= (in(i + 1) & 0xF0) >> 4 | ||
out.append(alphabet(b)) | ||
b = (in(i + 1) & 0x0F) << 2 | ||
if (i + 2 < in.length) { | ||
b |= (in(i + 2) & 0xC0) >> 6 | ||
out.append(alphabet(b)) | ||
b = in(i + 2) & 0x3F | ||
out.append(alphabet(b)) | ||
} else { | ||
out.append(alphabet(b)) | ||
out.append('=') | ||
} | ||
} else { | ||
out.append(alphabet(b)) | ||
out.append("==") | ||
} | ||
} | ||
out.result() | ||
} | ||
|
||
} |
28 changes: 28 additions & 0 deletions
28
scalapb-runtime/src/test/scala/com/trueaccord/scalapb/EncodingSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.trueaccord.scalapb | ||
|
||
import org.scalatest._ | ||
import org.scalatest.prop.GeneratorDrivenPropertyChecks | ||
|
||
class EncodingSpec extends PropSpec with GeneratorDrivenPropertyChecks with Matchers { | ||
property("fromBase64 is the inverse of toBase64") { | ||
forAll { | ||
b: Array[Byte] => | ||
Encoding.fromBase64(Encoding.toBase64(b)) should be(b) | ||
} | ||
} | ||
|
||
property("fromBase64 is compatible with javax.printBase64") { | ||
forAll { | ||
b: Array[Byte] => | ||
Encoding.fromBase64(javax.xml.bind.DatatypeConverter.printBase64Binary(b)) should be(b) | ||
} | ||
} | ||
|
||
property("toBase64 is compatible with javax.parseBase64") { | ||
forAll { | ||
b: Array[Byte] => | ||
javax.xml.bind.DatatypeConverter.parseBase64Binary( | ||
Encoding.toBase64(b)) should be(b) | ||
} | ||
} | ||
} |